事件循环机制EventLoop
Event Loop即事件循环,是解决javaScript单线程运行阻塞的一种机制。
一、JS 执行机制
在我们学js 的时候都知道js 是单线程的如果是多线程的话会引发一个问题在同一时间同时操作DOM 一个增加一个删除JS就不知道到底要干嘛了,所以这个语言是单线程的但是随着HTML5到来js也支持了多线程webWorker 但是也是不允许操作DOM。
单线程就意味着所有的任务都需要排队,后面的任务需要等前面的任务执行完才能执行,如果前面的任务耗时过长,后面的任务就需要一直等,一些从用户角度上不需要等待的任务就会一直等待,这个从体验角度上来讲是不可接受的,所以JS中就出现了异步的概念。
二、同步任务和异步任务
同步任务: 是调用立即得到结果的任务,同步任务在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务: 是调用无法立即得到结果,需要额外的操作才能预期结果的任务,异步任务不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。异步任务执行队列中先执行宏任务,然后清空当次宏任务中的所有微任务,然后进行下一个tick如此形成循环。
异步任务又可以分为以下两种(ES6):
-
1.宏任务
script(整体代码)、setTimeout、setInterval、postMessage、Ajax -
2.微任务
Dom操作、Promise、MutaionObserver、process.nextTick(Node.js 环境)
例题:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 这里整体的script代码作为第一个宏任务执行
async function Prom() {
console.log('Y')
await Promise.resolve() //微任务3 await之后的代码都将作为微任务进入任务队列
console.log('X')
}
setTimeout(() => { // 宏任务2
console.log(1)
Promise.resolve().then(()=>{ // 微任务4
console.log(2)
})
}, 0)
setTimeout(() => { // 宏任务3
console.log(3)
Promise.resolve().then(()=>{// 微任务5
console.log(4)
})
}, 0)
Promise.resolve().then(()=>{// 微任务1
console.log(5)
})
Promise.resolve().then(()=>{// 微任务2
console.log(6)
})
Prom()
console.log(0)
// 结果 Y 0 5 6 X 1 2 3 4
</script>
</body>
</html>
***结果分析:***首先肯定执行的是同步任务也就是调用Prom方法输出Y,然后最后一段输出的0;因为整体的script代码作为了第一个宏任务执行,此时要清空它下面的所有微任务1,2,3,由于Prom方法是在微任务1,2后面调用的,所以微任务3 在微任务1,2之后。此时一次循环结束,开始下次执行宏任务2,然后执行内部的微任务4。继续下次宏任务3,微任务5。