mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
feat: queueMicrotask()
error handling (#15522)
Adds error event dispatching for queueMicrotask(). Consequently unhandled errors are now reported with Deno.core.terminate(), which is immune to the existing quirk with plainly thrown errors (#14158).
This commit is contained in:
parent
e96933bc16
commit
97954003cc
8 changed files with 91 additions and 4 deletions
|
@ -2745,6 +2745,17 @@ itest!(report_error_end_of_program {
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(queue_microtask_error {
|
||||||
|
args: "run --quiet queue_microtask_error.ts",
|
||||||
|
output: "queue_microtask_error.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(queue_microtask_error_handled {
|
||||||
|
args: "run --quiet queue_microtask_error_handled.ts",
|
||||||
|
output: "queue_microtask_error_handled.ts.out",
|
||||||
|
});
|
||||||
|
|
||||||
itest!(spawn_stdout_inherit {
|
itest!(spawn_stdout_inherit {
|
||||||
args: "run --quiet --unstable -A spawn_stdout_inherit.ts",
|
args: "run --quiet --unstable -A spawn_stdout_inherit.ts",
|
||||||
output: "spawn_stdout_inherit.ts.out",
|
output: "spawn_stdout_inherit.ts.out",
|
||||||
|
|
5
cli/tests/testdata/queue_microtask_error.ts
vendored
Normal file
5
cli/tests/testdata/queue_microtask_error.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
queueMicrotask(() => {
|
||||||
|
throw new Error("foo");
|
||||||
|
});
|
||||||
|
console.log(1);
|
||||||
|
Promise.resolve().then(() => console.log(2));
|
6
cli/tests/testdata/queue_microtask_error.ts.out
vendored
Normal file
6
cli/tests/testdata/queue_microtask_error.ts.out
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
1
|
||||||
|
error: Uncaught Error: foo
|
||||||
|
throw new Error("foo");
|
||||||
|
^
|
||||||
|
at [WILDCARD]/queue_microtask_error.ts:2:9
|
||||||
|
at deno:core/[WILDCARD]
|
21
cli/tests/testdata/queue_microtask_error_handled.ts
vendored
Normal file
21
cli/tests/testdata/queue_microtask_error_handled.ts
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
addEventListener("error", (event) => {
|
||||||
|
console.log({
|
||||||
|
cancelable: event.cancelable,
|
||||||
|
message: event.message,
|
||||||
|
filename: event.filename,
|
||||||
|
lineno: event.lineno,
|
||||||
|
colno: event.colno,
|
||||||
|
error: event.error,
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
onerror = (event) => {
|
||||||
|
console.log("onerror() called", event.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
queueMicrotask(() => {
|
||||||
|
throw new Error("foo");
|
||||||
|
});
|
||||||
|
console.log(1);
|
||||||
|
Promise.resolve().then(() => console.log(2));
|
15
cli/tests/testdata/queue_microtask_error_handled.ts.out
vendored
Normal file
15
cli/tests/testdata/queue_microtask_error_handled.ts.out
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
1
|
||||||
|
{
|
||||||
|
cancelable: true,
|
||||||
|
message: "Uncaught Error: foo",
|
||||||
|
filename: "[WILDCARD]/queue_microtask_error_handled.ts",
|
||||||
|
lineno: 18,
|
||||||
|
colno: 9,
|
||||||
|
error: Error: foo
|
||||||
|
at [WILDCARD]/queue_microtask_error_handled.ts:18:9
|
||||||
|
at deno:core/[WILDCARD]
|
||||||
|
}
|
||||||
|
onerror() called Error: foo
|
||||||
|
at [WILDCARD]/queue_microtask_error_handled.ts:18:9
|
||||||
|
at deno:core/[WILDCARD]
|
||||||
|
2
|
|
@ -210,8 +210,35 @@
|
||||||
return aggregate;
|
return aggregate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reportExceptionCallback = undefined;
|
||||||
|
|
||||||
|
// Used to report errors thrown from functions passed to `queueMicrotask()`.
|
||||||
|
// The callback will be passed the thrown error. For example, you can use this
|
||||||
|
// to dispatch an error event to the global scope.
|
||||||
|
// In other words, set the implementation for
|
||||||
|
// https://html.spec.whatwg.org/multipage/webappapis.html#report-the-exception
|
||||||
|
function setReportExceptionCallback(cb) {
|
||||||
|
if (typeof cb != "function") {
|
||||||
|
throw new TypeError("expected a function");
|
||||||
|
}
|
||||||
|
reportExceptionCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
function queueMicrotask(cb) {
|
function queueMicrotask(cb) {
|
||||||
return ops.op_queue_microtask(cb);
|
if (typeof cb != "function") {
|
||||||
|
throw new TypeError("expected a function");
|
||||||
|
}
|
||||||
|
return ops.op_queue_microtask(() => {
|
||||||
|
try {
|
||||||
|
cb();
|
||||||
|
} catch (error) {
|
||||||
|
if (reportExceptionCallback) {
|
||||||
|
reportExceptionCallback(error);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some "extensions" rely on "BadResource" and "Interrupted" errors in the
|
// Some "extensions" rely on "BadResource" and "Interrupted" errors in the
|
||||||
|
@ -252,6 +279,7 @@
|
||||||
opCallTraces,
|
opCallTraces,
|
||||||
refOp,
|
refOp,
|
||||||
unrefOp,
|
unrefOp,
|
||||||
|
setReportExceptionCallback,
|
||||||
close: (rid) => ops.op_close(rid),
|
close: (rid) => ops.op_close(rid),
|
||||||
tryClose: (rid) => ops.op_try_close(rid),
|
tryClose: (rid) => ops.op_try_close(rid),
|
||||||
read: opAsync.bind(null, "op_read"),
|
read: opAsync.bind(null, "op_read"),
|
||||||
|
|
|
@ -76,7 +76,7 @@ delete Intl.v8BreakIterator;
|
||||||
const errors = window.__bootstrap.errors.errors;
|
const errors = window.__bootstrap.errors.errors;
|
||||||
const webidl = window.__bootstrap.webidl;
|
const webidl = window.__bootstrap.webidl;
|
||||||
const domException = window.__bootstrap.domException;
|
const domException = window.__bootstrap.domException;
|
||||||
const { defineEventHandler } = window.__bootstrap.event;
|
const { defineEventHandler, reportException } = window.__bootstrap.event;
|
||||||
const { deserializeJsMessageData, serializeJsMessageData } =
|
const { deserializeJsMessageData, serializeJsMessageData } =
|
||||||
window.__bootstrap.messagePort;
|
window.__bootstrap.messagePort;
|
||||||
|
|
||||||
|
@ -243,6 +243,7 @@ delete Intl.v8BreakIterator;
|
||||||
core.setMacrotaskCallback(timers.handleTimerMacrotask);
|
core.setMacrotaskCallback(timers.handleTimerMacrotask);
|
||||||
core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
|
core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
|
||||||
core.setWasmStreamingCallback(fetch.handleWasmStreaming);
|
core.setWasmStreamingCallback(fetch.handleWasmStreaming);
|
||||||
|
core.setReportExceptionCallback(reportException);
|
||||||
ops.op_set_format_exception_callback(formatException);
|
ops.op_set_format_exception_callback(formatException);
|
||||||
version.setVersions(
|
version.setVersions(
|
||||||
runtimeOptions.denoVersion,
|
runtimeOptions.denoVersion,
|
||||||
|
|
|
@ -3615,7 +3615,7 @@
|
||||||
"type-long-settimeout.any.worker.html": true
|
"type-long-settimeout.any.worker.html": true
|
||||||
},
|
},
|
||||||
"microtask-queuing": {
|
"microtask-queuing": {
|
||||||
"queue-microtask-exceptions.any.html": false,
|
"queue-microtask-exceptions.any.html": true,
|
||||||
"queue-microtask.any.html": true,
|
"queue-microtask.any.html": true,
|
||||||
"queue-microtask.any.worker.html": true
|
"queue-microtask.any.worker.html": true
|
||||||
},
|
},
|
||||||
|
@ -4610,4 +4610,4 @@
|
||||||
"idlharness.https.any.worker.html": true,
|
"idlharness.https.any.worker.html": true,
|
||||||
"idlharness-shadowrealm.window.html": false
|
"idlharness-shadowrealm.window.html": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue