Tools
Tools: Question of the Day #4 [Talk::Overflow]
2026-01-27
0 views
admin
🔹 The Question ## 🔹 Solution ## 🧠 How this works ## 🔍 Line-by-line explanation ## 🔹 Key Takeaways This post explains a quiz originally shared as a LinkedIn poll. Hint: In async functions, a return in finally can override the try return. Also, note when the continuation after await is enqueued relative to queueMicrotask. Correct output / order: start, end, micro, then cleanup This combines two behaviors that frequently surprise even experienced developers: So you get a deterministic ordering even though everything is “microtasks”. The non-obvious part: many people assume the queueMicrotask callback will run before “the rest of the async function”, because they picture the await continuation as “later”. But it was queued earlier in the same tick. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
console.log('start'); async function task() { try { return 'data'; } finally { await Promise.resolve(); return 'cleanup'; }
} task().then((v) => console.log('then', v));
queueMicrotask(() => console.log('micro'));
console.log('end'); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
console.log('start'); async function task() { try { return 'data'; } finally { await Promise.resolve(); return 'cleanup'; }
} task().then((v) => console.log('then', v));
queueMicrotask(() => console.log('micro'));
console.log('end'); COMMAND_BLOCK:
console.log('start'); async function task() { try { return 'data'; } finally { await Promise.resolve(); return 'cleanup'; }
} task().then((v) => console.log('then', v));
queueMicrotask(() => console.log('micro'));
console.log('end'); - finally can override return: in both sync and async functions, a return in finally wins over a return in try. Here, task() resolves to 'cleanup', not 'data'.
- Microtask ordering is “first queued, first run”: the await Promise.resolve() schedules the async function’s continuation as a microtask. That microtask is queued during the call to task(), before you later call queueMicrotask(...). - console.log('start') runs synchronously → prints start.
- task().then(...) calls task() immediately.
- Inside task(): try { return 'data' } is evaluated, but execution must still run finally.
In finally, await Promise.resolve() is hit: This schedules the continuation of task() as a microtask (call it R). task() returns a pending promise to the caller for now.
- try { return 'data' } is evaluated, but execution must still run finally.
- In finally, await Promise.resolve() is hit: This schedules the continuation of task() as a microtask (call it R). task() returns a pending promise to the caller for now.
- This schedules the continuation of task() as a microtask (call it R).
- task() returns a pending promise to the caller for now.
- Back in the outer script: queueMicrotask(() => console.log('micro')) queues another microtask (call it M) after R. console.log('end') runs synchronously → prints end.
- queueMicrotask(() => console.log('micro')) queues another microtask (call it M) after R.
- console.log('end') runs synchronously → prints end.
- Microtasks flush: R runs first (it was queued first): the async function resumes after await and executes return 'cleanup'. That resolves the promise returned by task() with 'cleanup'.
Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue. M runs next → prints micro. T runs last → prints then cleanup.
- R runs first (it was queued first): the async function resumes after await and executes return 'cleanup'. That resolves the promise returned by task() with 'cleanup'.
Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue.
- That resolves the promise returned by task() with 'cleanup'.
- Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue.
- M runs next → prints micro.
- T runs last → prints then cleanup. - try { return 'data' } is evaluated, but execution must still run finally.
- In finally, await Promise.resolve() is hit: This schedules the continuation of task() as a microtask (call it R). task() returns a pending promise to the caller for now.
- This schedules the continuation of task() as a microtask (call it R).
- task() returns a pending promise to the caller for now. - This schedules the continuation of task() as a microtask (call it R).
- task() returns a pending promise to the caller for now. - queueMicrotask(() => console.log('micro')) queues another microtask (call it M) after R.
- console.log('end') runs synchronously → prints end. - R runs first (it was queued first): the async function resumes after await and executes return 'cleanup'. That resolves the promise returned by task() with 'cleanup'.
Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue.
- That resolves the promise returned by task() with 'cleanup'.
- Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue.
- M runs next → prints micro.
- T runs last → prints then cleanup. - That resolves the promise returned by task() with 'cleanup'.
- Resolving it queues the .then(...) handler as a new microtask (call it T) at the end of the queue. - In JavaScript, return in finally overrides return in try (and can also override a throw).
- await splits execution: the continuation is scheduled as a microtask.
- Microtasks are ordered: work queued earlier in the tick runs first, even if it “feels” like it came from deeper async code.
- Treat return inside finally as a code smell unless you’re being very deliberate.
how-totutorialguidedev.toaijavascript