十分钟带你深入理解V8引擎的事件循环机制

前言

JavaScript作为一种单线程、非阻塞的语言,其执行模型是通过事件循环机制来实现的。所以理解JavaScript的运行原理,事件循环机制是一个关键的概念。

V8引擎作为JavaScript的主要运行时环境之一,其事件循环机制的实现细节也值得我们深入探讨。

正文

在了解事件循环机制之前,我们得补充一点前置知识

我们先来了解什么是同步代码异步代码

微任务宏任务又是什么呢?

1. 同步代码和异步代码:

  • 同步代码: 同步代码是按照代码的先后顺序依次执行的,一个任务必须等待前一个任务完成后才能执行。
  • 异步代码: 异步代码允许一个任务在执行的同时,其他任务也可以继续执行。当一个异步任务完成时,系统会通知,从而不会阻塞整个程序的执行。

2. 微任务和宏任务:

  • 微任务: 微任务是一种特殊的异步任务,它在当前代码块执行完成后立即执行,优先级比宏任务高。常见的微任务包括 Promise 的回调函数、MutationObserver 等。
  • 宏任务: 宏任务是常规的异步任务,它在当前代码块执行完成后执行,优先级比微任务低。常见的宏任务包括 setTimeout、setInterval、setImmedate()、I/O操作等。

image.png

既然我们已经知道了这些知识了

那我们开始讲解事件循环机制(Event Loop)的执行流程了

事件循环机制(Event Loop)的执行流程分为五步

  1. 执行同步代码(属于宏任务)
  2. 同步执行完毕后,检查是否有异步需要执行
  3. 如果有,则执行微任务队列中的所有任务
  4. 微任务队列执行完毕后,如果有需要就会渲染页面
  5. 执行异步宏任务,也是开启下一次时间循环

接下来我们通过代码去分析这五步流程

image.png

let a = 1;
console.log(a); // 1

setTimeout(() => {
  console.log(++a); 
}, 1000);

console.log(a); // 1
  1. 首先声明并赋值变量 a = 1
  2. 紧接着打印出 a 的值 1,其中像这些赋值操作都是同步代码。
  3. 然后遇到 setTimeout 函数,这是一个异步操作。V8 引擎会将这个异步任务放入宏任务队列中,等待适当的时机再执行。同时,主线程会继续执行下面的同步代码。
  4. 接下来打印出 a 的值 1。这时 a 的值还没有被修改。
  5. 1 秒钟后,setTimeout 的回调函数被执行。此时 a 的值为 1,打印出 1,然后 a 自增为 2

难度提升咯
image.png

console.log(1);
new Promise((resolve, reject) => {
  console.log(2);
  resolve();
})
  .then(() => {
    console.log(3);
  })
  .then(() => {
    console.log(4);
  });
setTimeout(() => {
  console.log(5);
});
console.log(6); // 12645
  1. 首先打印出 1
  2. 接下来创建一个新的 Promise 对象,在 Promise 构造函数中立即打印出 2
  3. Promise 的构造函数中 resolve() 被调用,这个 Promise 对象的状态变为 resolved。
  4. 然后 .then() 方法被调用,会将其中的回调函数作为微任务加入到微任务队列中。
  5. 紧接着又调用了一次 .then(),同样会将其回调函数加入微任务队列。
  6. 之后遇到了 setTimeout,它会将回调函数加入到宏任务队列中。
  7. 最后打印出 6

难度再升级

image.png

console.log(1);
new Promise((resolve, reject) => {
  console.log(2);
  resolve();
}).then(() => {
  console.log(3);
  setTimeout(() => {
    console.log(4);
  }, 0);
});
setTimeout(() => {
  console.log(5);
  setTimeout(() => {
    console.log(6);
  }, 0);
}, 0);
console.log(7); // 1273546
  1. 首先打印出 1
  2. 接下来创建一个新的 Promise 对象,在 Promise 构造函数中立即打印出 2
  3. Promise 的 resolve() 被调用,这个 Promise 对象的状态变为 resolved。
  4. 然后 .then() 方法被调用,会将其中的回调函数作为微任务加入到微任务队列中。
  5. .then() 回调函数中,首先打印出 3
  6. 然后遇到了 setTimeout,它会将回调函数加入到宏任务队列中,并设置延迟时间为 0 毫秒。
  7. 接下来遇到了另一个 setTimeout,它也会将回调函数加入到宏任务队列中,并设置延迟时间为 0 毫秒。
  8. 最后打印出 7

最后的考验,明白这个,你就完全理解了V8引擎的事件循环机制了
这里的细节之处就是await会将后续代码放入微任务队列中

image.png

console.log("script start");

async function async1() {
  await async2(); 
  console.log("async1 end");
}
async function async2() {
  console.log("async2 end");
}
async1();
setTimeout(function () {
  console.log("setTimeout");
}, 0);
new Promise(function (resolve, reject) {
  console.log("promise");
  resolve();
})
  .then(() => {
    console.log("then1");
  })
  .then(() => {
    console.log("then2");
  });
console.log("script end");
  1. 首先打印 "script start"
  2. 调用 async1() 函数,在这个函数中遇到 await async2()
  3. async2() 函数被执行,立即打印 "async2 end"
  4. 回到 async1() 函数,由于 await 的存在,async1() 函数会暂停执行,直到 async2() 完成,并且await会将后续代码放入微任务队列中。
  5. 然后创建了一个 Promise 对象,立即打印 "promise"
  6. 接下来打印 "script end"
  7. 由于 async1() 函数之前被暂停了,现在它可以继续执行,打印 "async1 end"
  8. 然后执行 Promise 的 .then() 回调,打印 "then1""then2"
  9. 最后执行 setTimeout 的回调,打印 "setTimeout"

总结

本文深入讲解了V8引擎的事件循环机制,相信看到这里的你一定会有收获的!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值