计算机系统的一种运行机制,JS用来解决单线程问题
一、问题
单线程语言,所有任务都在一个线程上完成,如果一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现"假死“,无法响应用户行为
如果采用多线程,多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说,这就太复杂了
二、解决方案
event loop:程序结构,用于等待和发送消息和事件
设置两个线程:一个主线程,负责程序本身的运行;一个event loop线程(消息线程),负责主线程和其它进程(主要是各种I/O操作)的通信
三、异步任务(宏任务、微任务)
1、js引擎执行任务时,会先执行同步任务,同步任务执行完成后,再执行异步任务
2、执行异步任务时,会先执行微任务,再执行宏任务
在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完
四、常见的宏任务
setTimeout、setInterval、requestAnimationFrame
对于setTimeout(fn,200),当到200ms时,fn会被放进“任务队列”,而“任务队列”必须要等到主线程已有的代码执行完才会执行fn,所以当程序执行到setTimeout(fn,200)这一行时,时间就开始计算,但是fn实际执行时并不一定是在200ms后,可能是在更久的时间后(取决于主线程上的同步代码的执行时间)
五、常见的微任务
MutationObserver、Promise.then catch finally
六、完整步骤
1、主线程先执行同步任务,遇到异步任务被加入到响应的任务队列,如宏任务队列(macrotask)、微任务队列(microtask);
2、同步任务执行完毕后,调用栈stack被清空,开始执行异步任务,异步任务会优先执行微任务,取出微任务队列队首的任务加入到stack中,直到微任务队列执行完毕。如果执行微任务过程中又遇到新的微任务,会被加入到微任务队列的末尾,在该任务周期调用完成(如果执行微任务过程中又遇到新的微任务,会被加入到微任务队列的末尾,在该任务周期调用完成);
3、微任务队列执行完成后,stack清空,开始执行宏任务队列,宏任务队列中如果遇到微任务,则优先执行微任务;
4、UI rending,执行时间是在所有的微任务执行完成后,下一个宏任务执行之前调用UI rending
接下来让我们用一段代码来看看吧
console.log(1); //同步任务
setTimeout(() =>{ //异步任务-宏任务
console.log(2); //同步任务
setTimeout(() =>{ //异步任务-宏任务
console.log(14); //同步任务
new Promise((resolve, reject) =>{
console.log(15); //同步任务
resolve(); //等价于promise().then()
}).then(res =>{ //异步任务-微任务
console.log(16); //同步任务
})
})
new Promise((resolve, reject) =>{
console.log(3); //同步任务
resolve(); //等价于promise().then()
}).then(res =>{
console.log(4); //同步任务
})
})
new Promise((resolve, reject) =>{
resolve(); //等价于promise().then()
}).then(res =>{ //异步任务-微任务
console.log(5); //同步任务
}).then(res =>{ //异步任务-微任务
console.log(6); //同步任务
})
new Promise((resolve, reject) =>{
console.log(7); //同步任务
resolve();//等价于promise().then()
}).then(res =>{ //异步任务-微任务
console.log(8); //同步任务
}).then(res =>{ //异步任务-微任务
console.log(9); //同步任务
})
setTimeout(() =>{ //异步任务-宏任务
console.log(10); //同步任务
new Promise((resolve, reject) =>{
console.log(11); //同步任务
resolve(); //等价于promise().then()
}).then(res =>{ //异步任务-微任务
console.log(12); //同步任务
})
})
结果:1、7、5、8、6、9、4、2、3、4、10、11、12、13、14、15、16
总结:JS代码是从上往下执行的,遇到同步任务会先执行,遇到异步任务会放到队列中,队列先进先出,异步任务又分为微任务和宏任务,JS在执行时会先执行微任务,在执行宏任务