Skip to content
本页目录

Event Loop

调用栈,后入先出

JS 中的任务

任务没有优先级,在消息队列中先进先出

同步任务(渲染主线程)

  • 解析 HTML
  • 解析 CSS
  • 样式计算
  • 处理图层
  • 页面渲染刷新 60/Hz
  • 执行全局 JS 代码
  • 执行事件
  • 执行定时器回调函数
  • ...

微任务(Microtasks,由 JS 引擎发起)

  • Promise.then().catch()Promise 是同步的,.then 或者 .catch 才是异步)
  • Async / Await
  • process.nextTick()
  • MutationObserver
  • Object.observe() 已废弃

宏任务(Macrotasks,由宿主环境发起(如浏览器、Node))

  • script(标签代码块)
  • 事件(如 addEventListener
  • 网络请求(ajax、fetch
  • setTimeout()、setIntever()

执行栈

问题

1. 什么是事件循环?

  • JS 引擎是单线程的,为了防止代码阻塞,浏览器将代码分为了同步任务与异步任务;
  • 同步任务的代码会被 JS 引擎立即执行,并放入到执行栈中,异步代码将会在触发后(如用户点击事件,setTimeout 回调等)被放入宿主环境的任务队列中(队列,先进先出);
  • 执行栈中的任务执行完毕后,会去任务队列中查看是否存异步任务,存在则将其放入执行栈中执行;
  • 这种反复从任务队列中查看异步任务并执行的过程,就是事件循环。

2. 什么是宏任务与微任务?

最新标准:因为浏览器的复杂度提升,W3C已不再使用宏任务队列说法,而是根据任务类型拆分为多种队列

chrome 的当前实现入下:

队列名称优先级说明
微队列最高原有的微任务队列
交互队列存放用户操作事件
延时队列较高存放定时器回调任务

3. 代码题

JS
new Promise(resolve => {
    resolve(1)

    new Promise(resolve => {
        resolve(2)
    }).then(res => {
        console.log(res)
    })
}).then(res => {
    console.log(res)
})

console.log(3)
new Promise(resolve => {
    resolve(1)

    new Promise(resolve => {
        resolve(2)
    }).then(res => {
        console.log(res)
    })
}).then(res => {
    console.log(res)
})

console.log(3)

答案: 3 2 1

4. 代码题

JS
console.log(1)
setTimeout(() => {
    console.log(2)

    new Promise(resolve => {
        resolve(3)
    }).then(res => {
        console.log(res)
    })
    console.log(4)
}, 0)

console.log(5)
console.log(1)
setTimeout(() => {
    console.log(2)

    new Promise(resolve => {
        resolve(3)
    }).then(res => {
        console.log(res)
    })
    console.log(4)
}, 0)

console.log(5)

答案:1 5 2 4 3

5. 代码题

JS
setTimeout(() => {
    console.log(1)
}, 0)

new Promise(resolve => {
    console.log(2)
    resolve(3)

    new Promise(resolve => {
        console.log(4)
        
        setTimeout(() => {
            console.log(5)
        }, 0)
        
        resolve(6)
    }).then(res => {
        console.log(res)
    })

    setTimeout(() => {
        console.log(7)
    }, 0)

}).then(res => {
    console.log(res)
})

console.log(8)
setTimeout(() => {
    console.log(1)
}, 0)

new Promise(resolve => {
    console.log(2)
    resolve(3)

    new Promise(resolve => {
        console.log(4)
        
        setTimeout(() => {
            console.log(5)
        }, 0)
        
        resolve(6)
    }).then(res => {
        console.log(res)
    })

    setTimeout(() => {
        console.log(7)
    }, 0)

}).then(res => {
    console.log(res)
})

console.log(8)

答案:2 4 8 6 3 1 5 7