mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -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,
|
||||
});
|
||||
|
||||
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 {
|
||||
args: "run --quiet --unstable -A spawn_stdout_inherit.ts",
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
|
@ -252,6 +279,7 @@
|
|||
opCallTraces,
|
||||
refOp,
|
||||
unrefOp,
|
||||
setReportExceptionCallback,
|
||||
close: (rid) => ops.op_close(rid),
|
||||
tryClose: (rid) => ops.op_try_close(rid),
|
||||
read: opAsync.bind(null, "op_read"),
|
||||
|
|
|
@ -76,7 +76,7 @@ delete Intl.v8BreakIterator;
|
|||
const errors = window.__bootstrap.errors.errors;
|
||||
const webidl = window.__bootstrap.webidl;
|
||||
const domException = window.__bootstrap.domException;
|
||||
const { defineEventHandler } = window.__bootstrap.event;
|
||||
const { defineEventHandler, reportException } = window.__bootstrap.event;
|
||||
const { deserializeJsMessageData, serializeJsMessageData } =
|
||||
window.__bootstrap.messagePort;
|
||||
|
||||
|
@ -243,6 +243,7 @@ delete Intl.v8BreakIterator;
|
|||
core.setMacrotaskCallback(timers.handleTimerMacrotask);
|
||||
core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
|
||||
core.setWasmStreamingCallback(fetch.handleWasmStreaming);
|
||||
core.setReportExceptionCallback(reportException);
|
||||
ops.op_set_format_exception_callback(formatException);
|
||||
version.setVersions(
|
||||
runtimeOptions.denoVersion,
|
||||
|
|
|
@ -3615,7 +3615,7 @@
|
|||
"type-long-settimeout.any.worker.html": true
|
||||
},
|
||||
"microtask-queuing": {
|
||||
"queue-microtask-exceptions.any.html": false,
|
||||
"queue-microtask-exceptions.any.html": true,
|
||||
"queue-microtask.any.html": true,
|
||||
"queue-microtask.any.worker.html": true
|
||||
},
|
||||
|
@ -4610,4 +4610,4 @@
|
|||
"idlharness.https.any.worker.html": true,
|
||||
"idlharness-shadowrealm.window.html": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue