Event Loop 这个概念相信大家或多或少都了解过,所谓温故而知新,so,今天,我们就从event loop出发,看看在事件的执行过程中,他都经历了些什么。
event loop是js的事件执行机制,我们一般简称为事件循环(之所以称作事件循环,是因为它经常被用于类似如下的方式来实现)
while (queue.waitForMessage()){
queue.processNextMessage();
}
如果当前没有任何消息queue.waitForMessage
会等待同步消息到达,当完成当前任务后,继续去查看有无需要执行的任务如果需要执行,就再次执行,如此循环,所以称之为事件循环。
要了解异步线程我们首先应该明白它的用处,因为js的单线程
特性,任务的执行顺序都是依次执行,而当我们在工作中遇到网络请求,前后端交互的时候,你的数据不会马上拿到,这需要时间,如果等拿到数据再执行下面的代码,这样如果多次请求就会发现加载速度极慢,这样显然不合理,这样就会出现很多次的暂停等待,所以这时候 需要执行异步任务,当我们发起请求时候,采用异步的方式,浏览器检测到其为异步时,就会开辟一个新的进程处理该函数,然后继续执行后面的任务,当完成了执行栈里的同步任务之后,再检测是否有异步任务需要执行,最后执行异步任务。
-同步任务进入主线程,按顺序从上而下依次执行,
-异步任务,进入`event table` ,注册回调函数 `callback` ,
任务完成后,将`callback`移入`event queue`中等待主线程调用
在执行过程中,我们知道了同步任务会优先异步任务执行,那么在异步中呢,异步中同样包含微任务和宏任务,首先我们大概了解下微任务和宏任务,在js中:
宏任务 #浏览器nodeI/O√√setTimeOut√√setInterval√√setImmediate×√requestAnimationFrame√×
微任务 #浏览器nodeprocess.nextTick×√MutationObserver√×Promise.then catch finally√√
这两种任务在不同环境下支持的各不同,今天我们主要看看在浏览器中,我们经常会遇到的有 promise
和 setTimeout
我们通过下面这段代���来看看:
console.log(1)
setTimeout(() => console.log(2), 0)
new Promise((resolve, reject) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
})
首先来分析下,这段代码中包含同步任务,包含异步的宏任务setTimeout
,包含异步的微任务promise
,这套题的答案是1.3.4.2 ,我们首先找到同步任务,1 3 是同步任务,然后执行异步任务,异步任务如果按顺序执行则是24 但是答案是4.2那么我们可以知道 promise的执行顺序优先于setTimeout所以由此可知,在异步任务中,微任务优先于宏任务执行,可以看看下图。
红线就是任务的执行顺序
黑线是任务的结构
看完这么多下面来完成下面这道题并加以分析:
console.log(1)
setTimeout(() => {
console.log(2)
new Promise((resolve, reject) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
})
}, 0)
new Promise((resolve, reject) => {
console.log(5)
resolve()
}).then(() => {
console.log(6)
})
setTimeout(() => {
console.log(7)
new Promise((resolve, reject) => {
console.log(8)
resolve()
}).then(() => {
console.log(9)
})
}, 0)
console.log(10)
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
答案:
1 , 5 , 10 , 6 , 2 , 3 , 4 , 7 , 8 , 9
废话不多说直接解题
console.log(1)
, 输出 1
setTimeout
宏任务, 将其回调函数推入 macro Task
的 event queue
中,macro Task
的 event queue
中记一个任务 setTimeout1
promise
微任务, 直接执行 new Promise
输出 5
, 并将 then
函数的回调函数推入 micro Task
的 event queue
中, micro Task
的 event queue
中记 一个 微任务 promise1
setTimeout
宏任务, 同理,将其回调函数推入 macro Task
的 event queue
中,macro Task
的 event queue
中记一个任务 setTimeout2
console.log(10)
, 输出 10上一轮事件循环结束,我们发现,已经输出
1 5 10
了, 按照我们之前所说,这个时候,主线程会去检查 是否存在微任务,不难发现,这个时候的event queue
是这个样子的
micro Task (微任务) | macro Task(宏任务) |
---|---|
promise1 | setTimeout1 |
setTimeout2 |
主线程 ---> promis1 ---> settimeout1 ---> settimeou2 ---> 循环检查主线程任务栈是否还有任务