浏览器的事件循环

248 阅读2分钟

一、为什么js浏览器中有事件循环的机制?

1.因为js是单线程在代码执行时,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行。

2.在执行同步代码时,如果遇到异步事件,js 引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当异步事件执行完毕后,再将异步事件对应的回调加入到一个任务队列中等待执行。

3.任务队列可以分为宏任务队列和微任务队列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务队列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行。当微任务队列中的任务都执行完成后再去执行宏任务队列中的任务。

二、两种任务

宏任务:整体代码、setTimeout、setIntervel、I/O操作

微任务:new Promise().then、MutaionObserver(前端回溯)

三、为什么要引入微任务的概念,只有宏任务可以吗?

宏任务先进先出的原则执行,并不能很好的控制任务的位置。如果这个时候有一个优先级比较高的任务需要去执行怎么办呢?只能等待前面的宏任务执行完再轮到它。所以为解决这一问题引入了微任务。

测试题目

第一题

async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout')
},0)
async1()
new Promise(function(resolve){
    console.log('promise1')
    resolve()
}).then(function(){
    console.log('promise2')
})
console.log('script end')

image.png

输出结果:

image.png

第二题

console.log('start')
setTimeout(()=>{
    console.log('children2')
    Promise.resolve().then(()=>{
        console.log('children3')
    })
},0)
new Promise(function(resolve,reject){
    console.log('children4')
    setTimeout(function(){
        console.log('children5')
        resolve('children6')
    },0)
}).then((res)=>{
    console.log('children7')
    setTimeout(()=>{
        console.log(res)
    },0)
})

输出结果

image.png

image.png

第三题

const p=function(){
    return new Promise((resolve,reject)=>{
        const p1=new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(1)
            },0)
            resolve(2)
        })
        p1.then((res)=>{
            console.log(res)
        })
        console.log(3)
        resolve(4)
    })
}
p().then((res)=>{
    console.log(res)
})
console.log('end')

输出结果

image.png

第四题

将resolve(2)去掉

image.png 输出结果

image.png