1

JavaScript 的事件机制

关于Event Loop,查阅多篇博客,或多或少总有些出入,在此写下自己关于Event Loop的理解

按同步与异步分

  • 首先判断JS是同步还是异步,同步就进入主进程,异步就进入event table
  • 异步任务在event table中注册函数,当满足触发条件后,被推入event queue
  • 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主进程中

按宏任务与微任务分 (更准确)

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval,setImmediate, I/O, UI rendering
  • micro-task(微任务):Promise.then,process.nextTick
许多地方把Promise标记为微任务,但是这容易让人误以为new Promise的时候这个过程是个微任务。其实是Promsie.then、Promise.catch是微任务,new Promise的时候当做普通的生成对象来看待,所以在此我标记为Promise.then
  • 执行本轮个宏任务

    • 过程中如果遇到微任务,是同步任务就将其放到微任务的[事件队列]里,异步放入微任务[事件表]中,注册函数,达到执行条件,推入微任务[事件队列]中 (目前为止我还不知道微任务有没有异步任务)
    • 遇到宏任务,是同步任务就将其放到宏任务的[事件队列]里,异步放入宏任务[事件表]中,注册函数,达到执行条件,推入宏任务[事件队列]中
  • 本轮宏任务执行完,查看微任务的[事件队列],并将里面全部的微任务依次执行完,从宏任务[事件队列]中执行下一轮宏任务

相关知识

  • JS单线程,这线程中只有一个唯一的事件循环
  • 一个线程中,事件循环是唯一的,但是可以有多个任务队列(微任务队列只有一个)
  • 任务队列分宏任务队列与微任务队列
那么问题来了,多个宏任务队列时,下一趟的宏任务该取哪个呢?上述方法中,我是将宏任务都看成一个队列的

Examples

/* example1 */
setTimeout(function () {
    console.log(1);
},7);

new Promise(function (resolve) {
    console.log(2);
    for (var i = 0; i < 10000; i++) {
        i == 99 && resolve();
    }
}).then(function () {
    console.log(3);
    setTimeout(() => {
        console.log(4);
    });
})

console.log(5);
// 2 3 5 (4 1) 后两个数字的顺序与两定时器的delayTime有关,谁先满足触发条件就先输出谁 (html5 标准中,规定delayTime >= 4ms)

/* example2 */
setTimeout(_ => console.log(4));

new Promise(resolve => {
    resolve()
    console.log(1)
}).then(_ => {
    console.log(3)
    Promise.resolve().then(_ => {
        console.log('before timeout')
    }).then(_ => {
        Promise.resolve().then(_ => {
            console.log('also before timeout')
        })
    })
})

console.log(2);
// 这个也不难,分析分析就出结果了

finally

综上 菜鸡二问

  • 微任务事件队列中存在异步任务嘛?
  • 多个宏任务事件队列,下一轮宏任务时该从哪个宏任务事件队列中取?
这些问题都需在不断的深入了解中才能知道答案
以上就是阅读多篇博客之后个人对Event Loop的一些见解,或有不正确之处,望批评指正

参考
前端基础进阶(十二):深入核心,详解事件循环机制
10分钟理解JS引擎的执行机制


晴天
31 声望1 粉丝