0、从个例子开始
//code-01
console.log(1)
setTimeout(() => {
console.log(2);
});
console.log(3);
稍微有点前端经验的人都知道这段代码输出的应该是 1 3 2
,因为setTimeout函数是异步执行。
那么都说js语言是单线程的,就是说是一件事从头到尾做完,那么它是怎么做到异步的呢?
这就要说到浏览器的运行机制了。
1、浏览器的基本机制
关于这部分内容目前了解不是很多,以后有时间再补上详细的内容。浏览器进程大致分为如下几个部分(从其他地方拷的图):
我们所说的js单线程,是指浏览器的js引擎线程
只有一个,用来执行js的代码,而浏览器的定时触发器线程
和事件触发器线程
结合,可以实现js语言的异步逻辑。那么js到底是怎么执行异步操作的呢?
我们来看下面这张流程图:
2、js语言事件循环机制-基础
我们来根据以上流程图,再来看 上面代码 code-01,
3、js语言事件循环机制-宏任务与微任务
经过上面的分析,我们对 事件循环机制有了初步的了解,现在我们再来看一个例子:
// code-02
console.log(1)
setTimeout(() => {
console.log(2);
});
new Promise(function(resolve){
console.log(3)
resolve()
}).then(function(){
console.log(4)
})
console.log(5);
上面代码的结果为1 3 5 4 2
,
我们知道 promise.then和setTimeout都是异步事件,那为什么then会比setTimeout先执行呢?
其实是因为上面流程图中 事件队列
其实应该分为 宏任务队列
和微任务队列
,微任务
优先于宏任务
,而且要等微任务队列
清空,才会去取宏任务队列
中的任务。
所以以上流程图应改为:
我们再来根据以上更新的流程图,再来看 上面代码 code-02,
那么到底有哪些异步任务是宏任务
,哪些是微任务
呢?
4、最后一个例子 - 最少延迟时间
我们再来看最后一个例子
setTimeout(() => {
console.log(1);
},2);
setTimeout(() => {
console.log(2);
},1);
setTimeout(() => {
console.log(3);
},0);
运行结果为 2 3 1
可能会有人疑惑,照以上的逻辑,不应该是 3 2 1
吗? 这是因为 setTimeout官方给出的规定是:最低延迟为 4ms,(这个有限制条件,但没怎么看懂)
但这个最低时间不同环境好像实现的不太一样
就上面代码而言,在Chorme浏览器中,最低延迟1ms,就是说 0ms 和 1ms 是同样的,
所以根据代码顺序,console.log(2)
比console.log(3)
先进入 宏任务队列
5、总结
参考
1.Event Loop的规范和实现
2.这一次,彻底弄懂 JavaScript 执行机制
3.setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop