从面试题看 JS 事件循环与 macro micro 任务队列
2023-11-17 23:48:10
前言
一个惬意的下午,朋友发来一道头条面试题,题目如下:
这个题目主要是考察对同步任务、异步任务:setTimeout、promise、async/await的执行顺序的理解程度。(建议大家也自己先做一下o) 当时由于我对async、await了解的不是很清楚,答案错的千奇百怪 :…
接到题目后,我怀着忐忑的心情开始了思考。由于我对 async、await 不是很熟悉,因此答案参差不齐。为了彻底弄清楚 JavaScript 中任务的执行顺序,我决定深入研究 JS 事件循环和 macro micro 任务队列。
揭秘 JS 事件循环
JS 事件循环是 JavaScript 引擎用来执行代码的一种机制。它是一个事件驱动的循环,这意味着它会不断地从事件队列中获取事件并执行它们。事件队列是一个先进先出的队列,这意味着最早进入队列的事件将首先被执行。
在事件循环中,任务被分为两类:宏任务和微任务。宏任务包括脚本、setTimeout 和 setInterval 等,而微任务包括 promise、async/await 和 MutationObserver 等。宏任务和微任务都在各自的队列中执行,宏任务队列优先于微任务队列。
微任务队列和宏任务队列
宏任务队列和微任务队列都是先进先出的队列,这意味着最早进入队列的任务将首先被执行。宏任务队列中的任务是 JavaScript 引擎执行的主体,而微任务队列中的任务是在宏任务执行期间执行的。
微任务队列的优先级高于宏任务队列,这意味着在宏任务执行期间,如果微任务队列中有任务,那么微任务队列中的任务将优先执行。
执行顺序之谜
现在,我们已经了解了 JS 事件循环和 macro micro 任务队列,那么我们就可以揭开 JavaScript 中任务的执行顺序之谜了。
在 JavaScript 中,同步任务会立即执行,而异步任务会稍后执行。同步任务包括变量声明、函数声明和函数调用等,而异步任务包括 setTimeout、setInterval、promise 和 async/await 等。
当 JavaScript 引擎执行代码时,它会首先执行同步任务。当所有的同步任务执行完毕后,它会检查微任务队列,如果微任务队列中有任务,那么它会执行微任务队列中的任务。当所有的微任务执行完毕后,它会检查宏任务队列,如果宏任务队列中有任务,那么它会执行宏任务队列中的任务。
常见的误解
关于 JavaScript 中任务的执行顺序,存在一些常见的误解。
- 误解一:setTimeout 是一个异步任务,因此它会在 promise 之后执行。
- 误解二:async/await 是一个同步任务,因此它会在 setTimeout 之前执行。
事实上,setTimeout 是一个宏任务,因此它会在 promise 之前执行。而 async/await 是一个语法糖,它可以让异步代码看起来像同步代码,但实际上它仍然是一个异步任务,因此它会在 setTimeout 之后执行。
总结
通过对 JS 事件循环和 macro micro 任务队列的深入理解,我们揭开了 JavaScript 中任务的执行顺序之谜。我们了解到,在 JavaScript 中,同步任务会立即执行,而异步任务会稍后执行。微任务队列的优先级高于宏任务队列,这意味着在宏任务执行期间,如果微任务队列中有任务,那么微任务队列中的任务将优先执行。
希望这篇文章能帮助您更好地理解 JavaScript 中任务的执行顺序。如果您有任何问题,欢迎随时与我联系。