1. 前言
这篇文章是想跟大家一起讨论一下javascript
中高大上的Event Loop事件循环机制
。
代码得仔细分析,能力绕的过去,否则容易绕晕,审慎再审慎~~~
事件循环次要讲的是异步执行问题,没方法,同步就是程序执行,没什么好说的。
<font color=gray>至于什么线程、同步异步、调用栈、浏览器线程之类的概念,本文一律没有,有意者可自行查阅。</font>
2. 简介
2.1 工作队列
- 宏工作队列:script整体代码、setTimeout/setInterval……
- 微工作队列:Promise
工作队列在事件循环机制中施展着核心作用。是咱们理解事件循环机制的外围因素。
2.2 执行程序
1. 无 async/await 的执行程序
留神点前置:
Promise中的函数属于同步函数
new Promise(function a(resolve, reject) { console.log('此为同步函数')})
- setTimeout、setInterval、 Promise.then等函数,不为实现状态的状况下,不会推送到工作队列中
图解:
流程图执行阐明:
- 首先执行同步代码
- 执行完结后查看微工作队列是否有工作,有则执行
- 微工作队列清空,查看宏工作队列是否有工作,有则执行
- 循环 2 和 3 。直至两个队列都清空
- 执行完结
栗子:
console.log('1');setTimeout(function() { console.log('2');}, 0)new Promise(function(resolve) { console.log('3'); resolve();}).then(function() { console.log('4');});console.log('5')
剖析:
- 首先执行同步代码,上述代码中
console.log(1)、console.log(3)
和console.log(5)
都属于同步代码。优先输入。同时执行延时函数、then函数,then函数立刻返回后果,推送到微工作队列中 - 查看微工作队列,有
console.log(4)
工作,执行并输入。微工作队列完结。 - 延时函数倒计时实现推入宏工作队列。
- 查看宏工作队列,有
console.log(2)
工作,执行并输入。宏工作队列完结。 - 代码执行完结。
- 输入程序:
1,3,5,4,2
2.async和await后的工夫循环机制
<font color=red>揭示: 局部文章会介绍 await 让出执行权的问题,这里先不探讨,容易绕晕。有趣味的能够查看以下。</font>
await代码的执行:
async标记的函数属于同步函数
async function log () { console.log('同步函数')}
await函数中返回一个promise,则执行后为
pending
状态,将下方的代码作为微工作解决,并且,只有await函数执行之后才会执行下方代码(请看栗子4)async function async2() { return new Promise(function(resolve) { console.log('3'); // 3 resolve(); }).then(function() { console.log('4'); // 6 });}console.log(async2()) // Promise { <pending> }
await函数中执行一个promise但不return 或者 resolve 被 setTimeout/setInterval 包裹,则执行后为 完结 状态,将下方的代码作为同步代码执行
// await函数中执行一个promise但不returnasync function async2() { // 区别在于没有return new Promise(function(resolve) { console.log('3'); // 3 resolve(); }).then(function() { console.log('4'); // 6 });}console.log(async2()) // Promise { undefined }// resolve 被 setTimeout/setInterval 包裹async function async2() { new Promise(function(resolve) { console.log('3'); setTimeout(() => { resolve(); }, 0) }).then(function() { console.log('4'); });}console.log(async2()) // Promise { undefined }
栗子1:
async function async1() { console.log('1'); await async2(); console.log('2');}async function async2() { return new Promise(function(resolve) { console.log('3'); resolve(); }).then(function() { console.log('4'); });}console.log('5'); setTimeout(function() { console.log('6'); }, 0)async1();new Promise(function(resolve) { console.log('7'); resolve();}).then(function() { console.log('8'); });console.log('9');
解析:
- 先执行同步,
console.log(5)、console.log(1)、console.log(3)、console.log(7)、console.log(9)
,将console.log(4)、console.log(8)
放入微工作队列。将console.log(6)
放入宏工作队列。 - 执行
console.log(4)
因为async2
返回的是promise
所以将前面的代码放入微工作队列中。此时微工作队列有两个工作console.log(8)、 console.log(2)
。清空微工作队列,输入8 和 2
。 - 执行宏工作队列。输入
6
- 输入程序
5,1,3,7,9,4,8,2,6
栗子2(栗子1的变种):
// 将async2改为上面这种写法,其余代码不变async function async2() { new Promise(function(resolve) { console.log('3'); resolve(); }).then(function() { console.log('4'); });}
解析:
- 栗子1的第一步放弃不变
- 扭转第二步,执行
console.log(4)
因为async2
返回的不是promise
所以间接执行前面的代码。输入2
此时微工作队列只有console.log(8)
清空微工作队列,输入8
。 - 栗子1的第三步放弃不变
- 输入程序:
5,1,3,7,9,4,2,8,6
栗子3(仍旧是栗子1的变种,最初一个小栗子):
async function async1() { console.log('1'); await async2(); console.log('2');}// 将async2中的resolve函数应用setTimeout包裹 且 return一个Promiseasync function async2() { return new Promise(function(resolve) { console.log('3'); setTimeout(() => { resolve(); }, 0) }).then(function() { console.log('4'); });}console.log('5');setTimeout(function() { console.log('6');}, 0)async1();new Promise(function(resolve) { console.log('7'); resolve();}).then(function() { console.log('8');});
解析:
- 先执行同步,
console.log(5)、console.log(1)、console.log(3)、console.log(7)、console.log(9)
,将console.log(8)
放入微工作队列。将console.log(6)和 console.log(4)
放入宏工作队列。 - 执行微工作
console.log(8)
,输入8
- 执行宏工作
console.log(6)
,输入6
- 因为
async2
返回一个Promise
,所以只能等到async2
执行之后才会将console.log(2)
推入到微工作队列。 - 执行宏工作
console.log(4)
,输入4
并将console.log(2)
推入到微工作中。 - 执行微工作
console.log(2)
,输入2
- 输入程序:
5,1,3,7,9,8,6,4,2
栗子4(真的是最初一个小栗子了):
// 将栗子3的async2函数改为如下写法async function async2() { new Promise(function(resolve) { console.log('3'); setTimeout(() => { resolve(); }, 0) }).then(function() { console.log('4'); });}
解析:
- 栗子3第一步不变
- 因为
async2
不返回Promise
,所以会将console.log(2)
作为同步代码执行,第二步执行同步工作console.log(2)
输入2
- 执行微工作
console.log(8)
,输入8
- 执行宏工作
console.log(6)
,输入6
- 执行宏工作
console.log(4)
,输入4
- 输入程序:
5,1,3,7,9,2,8,6,4
无论你是否认真的查看了下面的文章,首先祝贺你能够看到这里,事件队列始终是比拟难以了解的javascript
知识点。还是衷心的心愿这篇文章能带给你不一样的了解。也祝愿正在看文章的你技术越来越好。