Repository: angular
Issue: zone.js promises returning Unhandled Promise Rejection error even with catch blocks
Labels: area: zones,P3,bug

### 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.

```typescript
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

```true
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_