关于JavaScript中await推迟微任务至next tick的技术疑问
关于MDN中await“推迟至NEXT tick”描述的疑问解答
问题背景
根据MDN关于await的文档:
当代码中遇到await时(无论是在async函数还是模块中),被等待的表达式会执行,而所有依赖该表达式值的代码会被暂停并推入微任务队列。
async function foo(name) { console.log(name, "start"); console.log(name, "middle"); console.log(name, "end"); } foo("First"); foo("Second"); // 输出: // First start // First middle // First end // Second start // Second middle // Second end
在这种情况下,两个async函数实际上是同步的,因为它们不包含任何await表达式,三条语句在同一个tick中执行。
上述内容易于理解,但以下描述存在疑问:
然而,一旦存在一个await,函数就会变成异步的,后续语句的执行会被推迟至NEXT tick。
async function foo(name) { console.log(name, "start"); await console.log(name, "middle"); console.log(name, "end"); } foo("First"); foo("Second"); // 输出: // First start // First middle // Second start // Second middle // First end // Second end
疑问点:为何此处会描述为推迟至NEXT tick?按照事件循环机制,微任务应在当前tick中执行,而非下一个tick,这是否存在矛盾?
解答
这其实是MDN采用了简化表述,这里的“NEXT tick”和我们常说的“宏任务tick”不是同一个概念,本质上并不矛盾:
事件循环的tick划分:通常我们说的“当前tick”指的是一个宏任务的执行周期,包含同步代码执行+微任务队列清空。而MDN里的“NEXT tick”,实际指的是当前同步代码执行完毕后,微任务队列的执行阶段——相对于await之前的同步代码,后续代码确实是在“下一个执行批次”里运行,所以用“next tick”来简化描述这个异步阶段。
结合代码的执行流程:
- 调用
foo("First"),同步执行console.log("First start"),接着执行await后的console.log("First middle")(这部分是同步执行的),随后await会把后续的console.log("First end")包装成微任务,放入微任务队列。 - 当前同步代码未结束,继续调用
foo("Second"),同步执行console.log("Second start")和console.log("Second middle"),同样把console.log("Second end")放入微任务队列。 - 当当前宏任务的同步代码全部执行完毕后,立即清空微任务队列,依次执行
First end和Second end——这部分操作属于当前宏任务tick内的微任务阶段,并没有等到下一个宏任务tick。
- 调用
结论:MDN的描述是为了更直观地说明await会让后续代码脱离同步执行流,进入异步执行阶段,这里的“NEXT tick”是对微任务执行阶段的简化称呼,和事件循环中“微任务在当前宏任务tick内执行”的机制并不冲突。
内容的提问来源于stack exchange,提问作者AlexBor
相关产品推荐
相关产品推荐

