什么是Event Loop
Event Loop
一、进程和线程
1.进程:
资源分配的最小单位;应用程序的执行实例,每一个进程都是由私有的虚拟地址空间、代码、数据和其他系统资源所组成;进程拥有独立的堆栈空间和数据段,每当启动一个新的进程必须分配给他独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段。
2.线程:
程序执行的最小单位;线程是进程内的一个独立执行单元,在不同的线程之间是可以共享进程资源的;
线程拥有独立的堆栈空间,但是共享数据段,他们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高。
二、同步任务和异步任务
我可以将任务分为同步任务和异步任务,但是这并不准确。
1.同步任务:
同步任务就是在主线程上排队执行的任务,只能执行完一个再执行下一个。
2.异步任务:
异步任务则不进入主线程,而是现在 event table 中注册函数,当满足触发条件后,才可以进入任务队列来执行。只有任务队列通知主线程说,我这边异步任务可以执行了,这个时候此任务才会进入主线程执行。
3.举例
console.log("a");
setTimeout(function(){
console.log("b")
},1000)
console.log("c")
//"a" "c" "b"
/*
1.console.log("a")是同步任务,进入主线程执行,打印"a"
2.setTimeout 是异步任务,先被放入 event table 中注册,1000ms 之后进入任务队列
3.console.log("c")是同步任务,进入主线程执行,打印"c"
当"a","c"被打印后,主线程去事件队列中找到 setTimeout 里的函数,并执行,打印"b"
*/
三、宏任务和微任务
同步任务和异步任务的划分其实并不准确,准确的分类方式是宏任务(Macrotask)和微任务(Microtask)。
1.宏任务
宏任务包括:script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI rendering。
2.微任务
微任务包括:process.nextTick、Promise、MutationObserver(html5新特性)。
这种分类的执行方式就是,执行一个宏任务,过程中遇到微任务时,将其放到微任务的事件队列里,当前宏任务执行完后,会查看微任务的事件队列,依次执行里面的微任务。如果还有宏任务的话,再重新开启宏任务…
通俗的可以理解为,首先执行script(整体代码)宏任务,从上往下执行,遇到宏任务放入宏任务队列,遇到微任务放入微任务队列 => 执行微任务队列的任务,然后执行宏任务队列的第一个任务
=>执行script(整体代码)宏任务,从上往下执行,遇到宏任务放入宏任务队列,遇到微任务放入微任务队列
=>查看微任务队列并执行
=>执行宏任务队列的第一个任务
=>查看微任务队列并执行
=>执行宏任务队列的第二个任务
=>查看微任务队列并执行
=>执行宏任务队列的第三个任务
=>查看微任务队列并执行
....
3.举例
setTimeout(function(){
console.log("a")
})
new Promise(function(resolve){
console.log("b")
for(var i=0;i<10000;i++){
i==99 && resolve();
}
}).then(function(){
console.log("c")
})
console.log("d")
//"b" "d" "c" "a"
/*
1.首先执行 script 下的宏任务,遇到 setTimeout,将其放入宏任务的队列里
2.遇到 Promise,new Promise 直接执行,打印"b"
3.遇到 resolve=>then 方法,是微任务,将其放入微任务的队列里
4.遇到 console.log("d"),直接打印"d"
5.本轮宏任务执行完毕,查看微任务,发现 then 方法里的函数,打印"c"
6.本轮 event loop 全部完成
7.下一轮循环,先执行宏任务,发现宏任务队列中有一个 setTimeout,打印"a"
*/
console.log("a")
setTimeout(function(){
console.log("b")
process.nextTick(function(){
console.log("c")
})
new Promise(function(resolve){
console.log("d")
resolve();//如果没有执行 resolve,那么 then 方法不执行
}).then(function(){
console.log("e")
})
})
process.nextTick(function(){
console.log("f")
})
new Promise(function(resolve){
console.log("g")
resolve()//如果没有执行 resolve,那么 then 方法不执行
}).then(function(){
console.log("h")
})
setTimeout(function(){
console.log("i")
process.nextTick(function(){
console.log("j")
})
new Promise(function(resolve){
console.log("k")
resolve()
}).then(function(){
console.log("l")
})
})
//"a" "g" "f" "h" "b" "d" "i" "k" "c" "j" "e" "l"
//第一轮宏任务打印:"a" "g"
//第一轮微任务打印:"f" "h"
//第二轮宏任务打印:"b" "d"
//第二轮微任务打印:"c" "e"
//第三轮宏任务打印:"i" "k"
//第三轮微任务打印:"j" "l"
console.log("script start")
setTimeout(function () {
console.log("a")
setTimeout(function () {
console.log("b")
})
new Promise(function (resolve) {
console.log("c")
resolve();
}).then(function () {
console.log("d")
setTimeout(function () {
console.log("e")
})
})
})
new Promise(function (resolve) {
console.log("f")
resolve()
}).then(function () {
console.log("g")
})
setTimeout(function () {
console.log("h")
setTimeout(function () {
console.log("i")
})
new Promise(function (resolve) {
console.log("j")
resolve();
}).then(function () {
console.log("k")
setTimeout(function () {
console.log("l")
new Promise(function (resolve) {
console.log("m")
resolve()
}).then(function () {
console.log("n")
setTimeout(function () {
console.log("o")
})
})
})
})
})
//执行一个宏任务,检查并执行微任务队列
//最终打印顺序为:
//"script start" "f" "g" "a" "c" "h" "j" "k" "b" "e" "i" "l" "m" "n" "o"