Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试题整理 -- 1.JavaScript执行机制(单线程,通过Event Loop 事件循环执行异步) #17

Open
iwalking11 opened this issue Dec 28, 2018 · 5 comments

Comments

@iwalking11
Copy link
Owner

iwalking11 commented Dec 28, 2018

  1. JavaScript执行机制(单线程,通过Event Loop 事件循环执行异步)
console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

出处:
这一次,彻底弄懂 JavaScript 执行机制

@iwalking11
Copy link
Owner Author

iwalking11 commented Dec 28, 2018

1. task(macrotask)

一个 eventloop 有一或多个 task 队列。每个 task 由一个确定的 task 源提供。从不同 task 源而来的 task 可能会放到不同的 task 队列中。例如,浏览器可能单独为鼠标键盘事件维护一个 task 队列,所有其他 task 都放到另一个 task 队列。通过区分 task 队列的优先级,使高优先级的 task 优先执行,保证更好的交互体验。

task 源包括:(webappapis.html#generic-task-sources)

  • DOM 操作任务源:如元素以非阻塞方式插入文档
  • 用户交互任务源:如鼠标键盘事件。用户输入事件(如 click) 必须使用 task 队列
  • 网络任务源:如 XHR 回调
  • history 回溯任务源:使用 history.back() 或者类似 API

此外 setTimeout、setInterval、IndexDB 数据库操作等也是任务源。总结来说,常见的 task 任务有:

  • 事件回调
  • XHR 回调
  • IndexDB 数据库操作等 I/O
  • setTimeout / setInterval
  • history.back

2. microtask

每一个 eventloop 都有一个 microtask 队列。microtask 会排在 microtask 队列而非 task 队列中。

一般来说,microtask 包括:

  • Promise.then

Promise规范中提及 Promise.then 的具体实现由平台把握,可以是 microtask 或 task。当前的共识是使用 microtask 实现。

  • MutationObserver
  • Object.observe

3. 事件循环,宏任务,微任务的关系如图所示:

image

4. 总结

  1. 每个 eventloop 由三个阶段构成:执行一个 task,执行 microtask 队列,可选的 ui render 阶段, requestAnimationFrame callback 在 render 阶段执行。我们平时写的逻辑代码会被分类为不同的 task 和 microtask。
  2. microtask 中注册的 microtask 事件会直接加入到当前 microtask 队列。
  3. microtask 执行时机『尽可能早』,只要 javascript 执行栈为空,就会执行。一轮 eventloop 中,可能执行多次 microtask。
  4. requestAnimationFrame callback 的执行时机与浏览器的 render 策略有关,是黑箱的。
    参考:
    深入探究 eventloop 与浏览器渲染的时序问题

@iwalking11 iwalking11 changed the title 面试题整理 面试题整理 -- 1.JavaScript执行机制(单线程,通过Event Loop 事件循环执行异步) Dec 28, 2018
@iwalking11
Copy link
Owner Author

@iwalking11
Copy link
Owner Author

iwalking11 commented Feb 20, 2019

一道面试题引发的血案,下面进入主题
最新的chrome环境下(版本 72.0.3626.109),async1 end,promise2的执行顺序为async1 end在前,promise2在后。
因为async await 本身就是promise+generator的语法糖。所以await 后面的语法,肯定是作为micro task,不可能是macro task。
async1函数先执行,所以async2先加入micro task,因此async1 end先展示。这个看起来就比较合理点。目前看,不同浏览器实现不一样,没有统一的标准,不过最新的Node和chrome看样子已经修复过来了。

@iwalking11
Copy link
Owner Author

上面问题更详细的说明:
async await 和 promise微任务执行顺序问题

@zsjun
Copy link

zsjun commented Mar 8, 2019

其实js stack如果不空的话,是不会调用微任务的,
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants