mirror of
https://github.com/denoland/deno.git
synced 2024-12-21 23:04:45 -05:00
fix(core): run macrotasks and next ticks after polling dynamic imports (#17173)
This commit fixes handling of rejected promises in dynamic imports evaluation. Previously we were running callbacks for next ticks and macrotasks _before_ polling dynamic imports and checked for unhandled rejections immediately after. This is wrong, as `unhandledrejection` event is dispatched and its callbacks are run as macrotasks. This commit changes order of actions performed by the event loop to following: - poll async ops - poll dynamic imports - run next tick callbacks - run macrotask callbacks - check for unhandled promise rejections
This commit is contained in:
parent
2a61b5fdd4
commit
208c91b68f
8 changed files with 58 additions and 8 deletions
|
@ -2945,6 +2945,19 @@ mod run {
|
|||
output: "run/unhandled_rejection_sync_error.ts.out",
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/denoland/deno/issues/15661
|
||||
itest!(unhandled_rejection_dynamic_import {
|
||||
args: "run --allow-read run/unhandled_rejection_dynamic_import/main.ts",
|
||||
output: "run/unhandled_rejection_dynamic_import/main.ts.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/denoland/deno/issues/16909
|
||||
itest!(unhandled_rejection_dynamic_import2 {
|
||||
args: "run --allow-read run/unhandled_rejection_dynamic_import2/main.ts",
|
||||
output: "run/unhandled_rejection_dynamic_import2/main.ts.out",
|
||||
});
|
||||
|
||||
itest!(nested_error {
|
||||
args: "run run/nested_error.ts",
|
||||
output: "run/nested_error.ts.out",
|
||||
|
|
5
cli/tests/testdata/run/unhandled_rejection_dynamic_import/import.ts
vendored
Normal file
5
cli/tests/testdata/run/unhandled_rejection_dynamic_import/import.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
globalThis.addEventListener("unhandledrejection", () => {
|
||||
console.log("hey");
|
||||
});
|
||||
console.log("---");
|
||||
Promise.reject();
|
1
cli/tests/testdata/run/unhandled_rejection_dynamic_import/main.ts
vendored
Normal file
1
cli/tests/testdata/run/unhandled_rejection_dynamic_import/main.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
await import("./import.ts");
|
3
cli/tests/testdata/run/unhandled_rejection_dynamic_import/main.ts.out
vendored
Normal file
3
cli/tests/testdata/run/unhandled_rejection_dynamic_import/main.ts.out
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
hey
|
||||
error: Uncaught (in promise) undefined
|
3
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/import.ts
vendored
Normal file
3
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/import.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
a: "a",
|
||||
};
|
21
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/main.ts
vendored
Normal file
21
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/main.ts
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
globalThis.addEventListener("unhandledrejection", (e) => {
|
||||
console.log("unhandled rejection", e.reason);
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
const dummyImport = (await import("./import.ts")).default;
|
||||
|
||||
let a = new Promise((resolve, reject) => {
|
||||
throw "errA";
|
||||
});
|
||||
|
||||
let i = 0;
|
||||
while (true) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
i++;
|
||||
console.log("running...");
|
||||
|
||||
if (i > 3) {
|
||||
break;
|
||||
}
|
||||
}
|
5
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/main.ts.out
vendored
Normal file
5
cli/tests/testdata/run/unhandled_rejection_dynamic_import2/main.ts.out
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
unhandled rejection errA
|
||||
running...
|
||||
running...
|
||||
running...
|
||||
running...
|
|
@ -1127,12 +1127,7 @@ impl JsRuntime {
|
|||
self.pump_v8_message_loop()?;
|
||||
|
||||
// Ops
|
||||
{
|
||||
self.resolve_async_ops(cx)?;
|
||||
self.drain_nexttick()?;
|
||||
self.drain_macrotasks()?;
|
||||
self.check_promise_exceptions()?;
|
||||
}
|
||||
self.resolve_async_ops(cx)?;
|
||||
// Dynamic module loading - ie. modules loaded using "import()"
|
||||
{
|
||||
// Run in a loop so that dynamic imports that only depend on another
|
||||
|
@ -1157,9 +1152,13 @@ impl JsRuntime {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.check_promise_exceptions()?;
|
||||
}
|
||||
// Run all next tick callbacks and macrotasks callbacks and only then
|
||||
// check for any promise exceptions (`unhandledrejection` handlers are
|
||||
// run in macrotasks callbacks so we need to let them run first).
|
||||
self.drain_nexttick()?;
|
||||
self.drain_macrotasks()?;
|
||||
self.check_promise_exceptions()?;
|
||||
|
||||
// Event loop middlewares
|
||||
let mut maybe_scheduling = false;
|
||||
|
|
Loading…
Reference in a new issue