Event loop 事件循环机制
为什么会有事件循环机制这种说法?
因为JS的执行是单线程的,所执行的事件分为同步任务和异步任务,异步任务又分为宏任务和微任务。
JS的引擎需要严格遵循单线程的这种循环机制去执行这些事件对应的任务属性,所以作为一名合格的前端开发者,执行机制是每一个合格的前端开发所必须需要去了解的东西。
事件循环的执行顺序是怎样的?
同步任务 => 异步任务(微任务、宏任务)
JS引擎的执行顺序是,先去执行代码中的同步任务,在碰到异步任务的时候会标记异步任务的执行点(虚构),将这个异步任务放到任务队列里面,宏任务放宏任务队列,微任务放微任务队列。
在执行同步任务的过程中,只标记异步任务的执行点,不会处理任何异步任务的代码。
当所有的同步任务执行完毕后,开始执行标记的异步任务。
因为异步任务是按照标记点的顺序依次放入任务队列Task Queue里面,而队列Queue的特点是先进先出FIFO,所以在执行异步任务的时候会按照在执行同步任务所标记的执行点时的先后顺序依次去执行放入队列内的异步任务,先放入的先执行,后放入的后执行。
异步任务的执行过程
微任务 ==> 宏任务 ==> 微任务 ==> 宏任务 ==> 微任务==> ................
注:每次在执行宏任务之前必定会去微任务的队列里面查找是否有微任务,如果有微任务先执行一个微任务,俗称:插队
宏任务 Marco task
setTimeout 、setInterval、setImmediate、fs.readFile()、网络请求Ajax、axios、script、事件 、I/O
微任务 Micro task
Promise.then() 、process.nextTick、Object.observe 、MutationObserver
注:Promise的实例化是一个同步任务,其中的同步代码放在主线程中做同步任务执行。
如以下代码是同步任务
const P = new Promise(
function() {
console.log('我是一个同步任务,因为我在Promise的实例化对象里面');
resolve('我是这个实例化的状态码,也是一个同步任务,如果没有resolve的话,pending状态就是我的实例化同步任务的状态码传给then')
}
);
p.then(res=>{console.log('我在then里面,永远做微任务来执行')},rej=>{console.log('我也是')})
练习题 1
console.log(1)
setTimeout(function() {
console.log(2)
new Promise(function(resolve) {
console.log(3)
resolve()
}).then(function() {
console.log(4)
})
})
new Promise(function(resolve) {
console.log(5)
resolve()
}).then(function() {
console.log(6)
})
setTimeout(function() {
console.log(7)
new Promise(function(resolve) {
console.log(8)
resolve()
}).then(function() {
console.log(9)
})
})
console.log(10)
//打印结果:1,5,10,6,2,3,4,7,8,9
练习题2
new Promise((resolve, reject) => {
resolve(1)
new Promise((resolve, reject) => {
resolve(2)
}).then(data => {
console.log(data)
})
}).then(data => {
console.log(data)
})
console.log(3)
//打印结果: 3,2,1