mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -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",
|
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 {
|
itest!(nested_error {
|
||||||
args: "run run/nested_error.ts",
|
args: "run run/nested_error.ts",
|
||||||
output: "run/nested_error.ts.out",
|
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()?;
|
self.pump_v8_message_loop()?;
|
||||||
|
|
||||||
// Ops
|
// Ops
|
||||||
{
|
|
||||||
self.resolve_async_ops(cx)?;
|
self.resolve_async_ops(cx)?;
|
||||||
self.drain_nexttick()?;
|
|
||||||
self.drain_macrotasks()?;
|
|
||||||
self.check_promise_exceptions()?;
|
|
||||||
}
|
|
||||||
// Dynamic module loading - ie. modules loaded using "import()"
|
// Dynamic module loading - ie. modules loaded using "import()"
|
||||||
{
|
{
|
||||||
// Run in a loop so that dynamic imports that only depend on another
|
// Run in a loop so that dynamic imports that only depend on another
|
||||||
|
@ -1157,9 +1152,13 @@ impl JsRuntime {
|
||||||
break;
|
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
|
// Event loop middlewares
|
||||||
let mut maybe_scheduling = false;
|
let mut maybe_scheduling = false;
|
||||||
|
|
Loading…
Reference in a new issue