Repository navigation
Description
Which @angular/* package(s) are the source of the bug?
zone.js
Is this a regression?
No
Description
I've hit the same issue as described in #31680 and both this and that ticket have same root cause detailed bellow. Since I cannot reopened old issue I've created a new one. That older ticket was closed with a fix that was for a separate issue and the fix was not relevant or helped in anyway.
Repro
Following simplified code will emit unhandled promise rejection even tho there is a catch handler. This happens only when zone.js is loaded. Without zone.js, all majors browsers (Chrome, Safari, Firefox) don't report anything in this case.
onunhandledrejection = (e) => { console.log("Unhandled promise rejection", e) }
(async function() {
return Promise.reject(1);
})().catch(e => {});
// OR
(async function() {
await Promise.reject(2);
})().catch(e => {});Using native Promise.reject will not emit unhandled rejection.
Root cause:
zone.js schedules the reporting of unhandled rejections on the microtask queue as soon as the promise is rejected. In the case of Promise.reject it schedules as part of the reject call.
JS async function calls .then on the returned inner promise (Promise.reject) on the next microtask tick. This is defined in the Ecmascript spec.
zone.js will end up running the code to report unhandled rejections before JS async function has a chance to call then and as such zone.js ends emiting unhandled rejection.
All major browsers check if unhandled rejections exists at the end of the microtask checkpoint (i.e. after draining the queue) and if needed will schedule on normal queue a task (or what you call a macro task) to process&report unhandled rejections. This allows sufficient time for the async infrastructure to hook to the returned promise. In Chrome and Safari it even allows sufficient time to add catch handler in a callback run by setTimeout of delay 0.
Chrome:
https://github.com/chromium/chromium/blob/89e00b6b959f5efb4bd7eec468973badb3093a3b/third_party/blink/renderer/platform/scheduler/common/event_loop.cc#L108
https://github.com/chromium/chromium/blob/89e00b6b959f5efb4bd7eec468973badb3093a3b/third_party/blink/renderer/bindings/core/v8/rejected_promises.cc#L248-L252
Firefox:
https://github.com/mozilla/gecko-dev/blob/77dd6aa3810610949a5ff925e24de2f8c11377fd/xpcom/base/CycleCollectedJSContext.cpp#L473-L480
Safari:
https://github.com/WebKit/WebKit/blob/75a3eb3a5fe3dce1867d880faf785137963b234a/Source/WebCore/dom/Microtasks.cpp#L107
https://github.com/WebKit/WebKit/blob/75a3eb3a5fe3dce1867d880faf785137963b234a/Source/WebCore/dom/RejectedPromiseTracker.cpp#L142-L144
Please provide a link to a minimal reproduction of the bug
No response
Please provide the exception or error you saw
Unhandled Promise rejection: 1 ; Zone: <root> ; Task: null ; Value: 1 undefined
Unhandled Promise rejection: 2 ; Zone: <root> ; Task: null ; Value: 2 undefined
Unhandled promise rejection PromiseRejectionEvent {isTrusted: true, reason: 1, type: 'unhandledrejection' ...}
Uncaught (in promise) 1
Unhandled promise rejection PromiseRejectionEvent {isTrusted: true, reason: 2, type: 'unhandledrejection' ...}
Uncaught (in promise) 2
Please provide the environment you discovered this bug in (run ng version)
No response
Anything else?
No response
Activity
JoostK commentedon Aug 11, 2023
Seems related to #47562 (specific to
finally) and open PR #49589.ioancris commentedon Aug 11, 2023
That PR won't fix this issue.
This issue has a different root cause.
ioancris commentedon Aug 14, 2023
Here is a snipper of code that can workaround the above issue in zone.js
I'll note that zone.js has another bug that above doesn't try to fix, this time for the rejections handled event. This event should only be sent after a corresponding unhandled rejection event but zone.js sometimes sends it earlier and without a corresponding unhandled rejection. To implement the spec requires to store the promises who have unhandled rejections and this needs to use weak reference (e.g. WeakMap or WeakSet) and storage should have a bound since there is no guarantee that promise rejection will ever get handled. I think I saw Chrome have 1000 limit for how many promises it stores.
See 6.2 step from the spec that defines what to do in case of promise rejection handled.
kavitshah8 commentedon Aug 22, 2023
@ioancris We came to know the following from opentelemetry-context-zone-peer-dep.
Hence, zone.js does not work as expected with
async ... await.JeanMeche commentedon Aug 22, 2023
Zone.js doesn't work with async/await. That's why angular uses a babel plugin to transform async/await into generator functions.
nicetomytyuk commentedon Jun 4, 2024
Is there any update on it?
RayhanulRumel commentedon Jun 6, 2024
I see these errors when I open my app using Safari on my iPhone. However, I don't get these errors by using a laptop with different browsers like Opera, Chrome, and Firefox. Is there any fix to it now?
fix(zone.js): allow draining microtasks in `Promise.then` (through flag)
fix(zone.js): allow draining microtasks in `Promise.then` (through flag)
fix(zone.js): allow draining microtasks in `Promise.then` (through flag)
fix(zone.js): allow draining microtasks in `Promise.then` (through flag)
angular-automatic-lock-bot commentedon May 16, 2026
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.