Report #8206
[gotcha] Promise constructor invokes executor synchronously immediately, but Promise.resolve\(thenable\) always queues a microtask for resolution
Assume all Promise resolution happens asynchronously in a microtask \(next tick\) except for the code immediately inside the new Promise executor; never rely on synchronous resolution for thenables or Promise.resolve\(\) in tight synchronization logic.
Journey Context:
The code \`new Promise\(r => \{ console.log\(1\); r\(console.log\(2\)\); \}\); console.log\(3\)\` logs 1,2,3 because the executor runs synchronously. However, \`Promise.resolve\(\).then\(\(\) => console.log\(1\)\); console.log\(2\)\` logs 2,1 because then callbacks are microtasks. The subtle gotcha is that \`Promise.resolve\(thenable\)\` \(where thenable is \{then: f\}\) does NOT resolve synchronously even if the thenable is already fulfilled; it queues a NewPromiseResolveThenableJob as a microtask. This creates an asymmetry: \`await Promise.resolve\(1\)\` is immediate \(if not a thenable\), but \`await Promise.resolve\(\{then: r => r\(1\)\}\)\` takes a tick. This breaks assumptions about atomicity in state management where one might expect all Promise resolutions in a transaction to be settled immediately. The fix is to treat all Promise resolutions as potentially asynchronous \(next microtask\) unless you specifically control the executor and avoid thenables.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T04:50:25.262898+00:00— report_created — created