本文是笔者花了点时间重新学习了下 javascript 中的事件循环总结的个人博客,本文的例子是网上摘录,仅供学习哈~
认识 Event Loop
Javascript 语言的最大特点就是单线程,这也就意味着引擎只有在执行完前一个任务后才会执行后一个任务。就算前置任务耗时长,后续任务也不能执行,就想现实中的飞行航班的前序航班延误,那么后续航班也会因此延误。
正是因为此特性,所以 JS 中有了任务队列这说法,任务队列是一个先进先出的数据结构,前面的事件会优先被主线程读取。主线程循环不断从任务队列中读取事件执行这种运行机制就叫 Event Loop。
任务又分为同步任务(synchronous)和异步任务(asynchronous)。同步任务是指在主线程上排队待执行的任务;异步任务是指不进入主线程,而进入任务队列的任务。当异步任务可以执行时才进入任务队列,等待主线程空闲时读取执行。
运行机制:
- 主线程依次执行所有同步任务,形成一个任务执行栈。
- 主线程如果执行异步任务,任务有结果之后,将回调事件加入任务队列。
- 主线程所有同步任务执行完毕,系统依次读取任务队列事件加入执行栈并执行,如果有新的异步事件会形成新的任务队列。
- 主线程重复直至所有任务执行完毕。
不同的异步任务也被分为两类:微任务(micro task)和宏任务(macro task)。
宏任务:
- setTimeout()
- setInterval()
- setImmediate (Nodejs 环境)
微任务:
- promise.[then/catch/finally]
- process.nextTick(Nodejs 环境)
- Object.observe
在一个事件循环中,异步事件返回结果会被放到任务队列中,根据异步事件的类型会被放入对应的宏任务队列或者微任务队列。当当前执行栈为空时,主线程会查看微任务队列并执行所有任务直至微任务队列为空,然后从宏任务队列取出一个事件推入执行栈,如此反复。
同一次事件循环中,微任务永远在宏任务前执行。
几个例子
举例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| console.log('script start'); async function async1() { await async2(); console.log('async1 end'); } async function async2() { console.log('async2 end'); } setTimeout(function () { console.log('setTimeout'); }, 0); new Promise((resolve) => { console.log('Promise'); resolve(); }) .then(function () { console.log('promise1'); }) .then(function () { console.log('promise2'); }); async1(); console.log('script end');
|
结果:
1 2 3 4 5 6 7 8
| script start Promise async2 end script end promise1 async1 end promise2 setTimeout
|
举例 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| console.log('sync statement 1'); Promise.resolve() .then(function () { console.log('micro task 1'); setTimeout(function () { console.log('macro task 1'); }, 0); }) .then(function () { console.log('micro task 2'); });
setTimeout(function () { console.log('macro task 2'); Promise.resolve().then(function () { console.log('micro task 3'); }); }, 0); console.log('sync statement 2');
|
结果:
1 2 3 4 5 6 7
| sync statement 1 sync statement 2 micro task 1 micro task 2 macro task 2 micro task 3 macro task 1
|
举例 3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| console.log('1'); setTimeout(function () { console.log('2'); new Promise(function (resolve) { console.log('3'); resolve(); }).then(function () { console.log('4'); }); }, 0); new Promise(function (resolve) { console.log('5'); resolve(); }).then(function () { console.log('6'); }); setTimeout(function () { console.log('7'); new Promise(function (resolve) { console.log('8'); resolve(); }).then(function () { console.log('9'); }); });
|
结果: