大家可能都遇到过类似的面试题
console.log(1);
setTimeout(()=>{
console.log(3)
},0);
console.log(2);
结果输出为 1 2 3
为什么结果不是1,3,2呢,我们明明只设置了0毫秒的延迟,下面让我们来看看到底是怎么回事
首先先用大白话简单介绍几个概念
我们都知道js是单线程的,什么是单线程,说白了就是js在同一时间只能做一件事,这就是单线程
那么什么是任务队列呢,我们都知道事件、ajax这些是异步操作,当我点击某个按钮时会通过回调函数执行某些操作,当我去请求接口的时候浏览器不用一直等着,它可以去做别的事情,当请求成功时会自动调起成功回调,那么这和js的单线程看起来是冲突的,那它又是怎么做到的呢,其实就是任务队列
说到任务队列这么还有概念,同步任务,异步任务, 像settimeout,ajax,promise这种就属于异步任务,像上述代码中的console.log(1)就属于同步任务
js代码是从上到下执行的,遇到异步任务要挂起,也就是说上面代码的settimeout会先挂起,先不执行,此时代码继续向下执行console.log(3),当同步任务都执行完成后才会去执行异步任务
所以刚才输出的结果是 1,2,3
下面我们来看下一道题
console.log("a")
while(1){
}
console.log("b")只打印出a, 因为都是同步任务,while循环会一直执行,所有打印不出来b
那么我们再来看一道题
console.log("a");
setTimeout(()=>{
console.log("b")
},0);
while(1){}还是会只打印a,因为异步任务会当放到同步任务之后执行,所以b还是打印不出来
接下来再看一道题
for(var i=0;i<4;i++){
setTimeout(()=>{
console.log(i)
},0)
}最终会输出 4,4,4,4,for循环是一个同步任务,会先执行,此时会把setTimeout交给浏览器的time模块(主要是处理setTimeout,setInterval的),用不了1毫秒,循环执行完成,而此时r任务队列里还没有任务,只有setTimeout的时间(虽然我们设置的是0,但浏览器最小大概是4毫秒)到了,浏览器的Time模块才会把setTimeout的回调函数放到任务队列里,任务队列再等待一个叫event loop(后面会讲) 的东西来执行,这道题讲的是异步任务的放入时间和执行的时间
什么是event loop

执行栈(stack)会执行同步任务,当遇到异步任务,浏览器的js引擎会将异步任务拿走,比如setTimeout,浏览器的time模块会将setTimeout拿走,当时间到了,会把回调函数放到任务队列(callback queue),当同步任务执行完成后,js引擎会去任务队列里看看有没有要执行的东西,发现里面有东西就会把它拿到执行栈中执行,此时setTimeout就变成了执行栈中的同步任务,当setTimeout执行完,执行栈又空了,js引擎会去任务队列中看看有没有其他需要执行的任务,如此往复的过程就是event loop
异步任务有哪些
setTimeout,setInterval
DOM事件
promise
MutationObserve
MessageChannel等
看下面代码
console.log(1);
setTimeout(function(){
console.log(2);
});
Promise.resolve(1).then(function(){
console.log('promise')
})会输出 1 , promise , 2
因为异步任务中又分为宏任务和微任务
微任务包括
promise里的then,
MutationObserve
MessageChannel
宏任务包括
setTimeout,setInterval
在浏览器端微任务的执行会优先于宏任务,而在node里会怎么样呢
再来看一段代码
console.log(1);
setTimeout(function(){
console.log(2);
Promise.resolve(1).then(function(){
console.log('promise')
})
})
setTimeout(function(){
console.log(3);
})在浏览器中会输出 1,2,promise,3
而用node运行则会输出 1,2,3,promise

在node中执行到相应的任务队列时,会把任务队列清空,里面的任务依次放到执行栈中执行,然后在去执行下一队列。
未完待续
如有错误,欢迎指正。图片均来自网络,侵删