前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS:事件循环机制(Event Loops)

JS:事件循环机制(Event Loops)

作者头像
前端小tips
发布2021-12-08 17:06:56
1.5K0
发布2021-12-08 17:06:56
举报
文章被收录于专栏:前端文章小tips

1. **在深入了解事件循环之前,我们不妨先做道题**

思考下面代码的执行结果

setTimeout(() => {

console.log(1)

}, 0)

new Promise((resolve, reject) => {

console.log(2)

resolve(3)

}).then(val => {

console.log(val)

})

console.log(4)

输出结果是:

2

4

3

1

你做对了吗?这里我们不禁要问:

* 为什么 `setTimeout()` 设定的时间是 0 毫秒,但 1 却是在最后输出的?

* 为什么 `Promise.then()` 的回调函数会在 4 输出之后执行,而不是在 2 之后?

其实,在 JavaScript 中,代码的执行顺序并不是完全按照它们的书写顺序,而是取决于它们在 **事件循环** 中的顺序。

2. **什么是事件循环?**

事件循环,即 Event Loops。用于协调事件、用户交互、JavaScript 脚本、DOM 渲染、网络请求等等的执行顺序问题。

一个遵循 ECMAScript 标准的代理(浏览器或 JS 引擎)也必须遵循事件循环机制。

事件循环是由一个或以上的 **任务队列** 组成的。

3. **什么是任务队列?**

任务队列,即 Task Queues,是一组任务的集合(Sets)。

由于 JavaScript 是 **单线程** 语言,所以在 JS 中所有的任务都需要排队执行,这些任务共同组成了 **任务队列**

,依次排队执行的过程,形成一个 **执行栈(Execution Context Stack)** 。

在任务队列中最先执行是同步任务。

4. **什么是同步任务?**

同步任务,即 Synchronous Task。就是当上一个任务执行完成后,接下来可以立即执行的任务。它们在主线程上依次排队执行,直到清空。

比如,下面代码中的 `for()` 和 `console.log()` 将会依次执行,最终输出 `0 1 2 done`。

for (let i = 0; i < 3; i++) {

console.log(i)

}

console.log('done')

与同步任务相比,异步任务的执行充满了不确定性。

5. **什么是异步任务?**

异步任务,即 Asynchronous

Task。就是需要等待被通知才以执行的任务。也就是说,它们不会直接进入主线程执行,而是进入到微任务队列或下一次事件循环中的任务队列进行等待。

常见的异步任务有:

* `XMLHttpRequest()`

* `Promise.then()`、`Promise.catch()`、`Promise.finally()`

* `setTimeout()`、`setInterval()`

等待,就意味着不确定性。比如,`XMLHttpRequest()` 等待服务器响应,`Promise.then()` 等待

`resolve()`,`setTimeout()` 等待时间。

所以虽然都是异步任务,它们的执行的顺序仍然会有所区别。因此,我们将它们分为 **宏任务** 和 **微任务** 。

6. **什么是宏任务?**

宏任务,即 MacroTask。就是指进入任务队列的任务。比如:

* `setTimeout()`、`setInterval()`

* `document.appendChild()`

* [`postMessage()`](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FWindow%2FpostMessage)

* [`MessageChannel()`](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FMessageChannel)

* [`setImmediate()`](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FWindow%2FsetImmediate)(Node.js 环境)

* `<script />`

由于当前任务队列已经处于执行状态,所以任务队列中遇到的宏任务将进入到下一次事件循环的任务队列,而微任务则会被放入到本次事件循环的微任务队列中。

7. **什么是微任务?**

微任务,即 Microtask 或 Jobs。每次事件循环都会有一个初始为空的微任务队列。常见的微任务有:

* `Promise.then()`、`Promise.catch()`、`Promise.finally()`

* [`MutationObserver()`](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FMutationObserver)(浏览器环境)

* `process.nextTick()`(Node.js 环境)

8. 测试题

看到这里,JavaScript 的事件循环机制差不多就解释完了,涉及到了同步任务、异步任务、宏任务和微任务以及它们之间的关系。

下面有几道测试题,同学们可以测试一下自己的理解程度:

* 简单

setTimeout(() => {

console.log(1)

}, 0)

for (let i = 2; i <= 3; i++) {

console.log(i)

}

console.log(4)

setTimeout(() => {

console.log(5)

}, 0)

for (let i = 6; i <= 7; i++) {

console.log(i)

}

console.log(8)

* 普通

console.log(1)

async function async1() {

await async2()

console.log(2)

}

async function async2() {

console.log(3)

}

async1()

setTimeout(() => {

console.log(4)

}, 0)

new Promise(resolve => {

console.log(5)

resolve()

})

.then(() => {

console.log(6)

})

.then(() => {

console.log(7)

})

console.log(8)

* 困难

console.log(1)

function a() {

return new Promise(resolve => {

console.log(2)

setTimeout(() => {

resolve()

console.log(3)

}, 0)

})

}

a().then(() => {

console.log(4)

})

* * *

参考资料:

* [ECMAScript® 2022 Language Specification](https://links.jianshu.com/go?to=https%3A%2F%2Ftc39.es%2Fecma262%2F%23sec-agents)

* [HTML Standard](https://links.jianshu.com/go?to=https%3A%2F%2Fhtml.spec.whatwg.org%2Fmultipage%2Fwebappapis.html%23event-loops)

* [并发模型与事件循环 - JavaScript | MDN](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FJavaScript%2FEventLoop)

* [window.setTimeout - Web API 接口参考 | MDN](https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FWindowOrWorkerGlobalScope%2FsetTimeout)

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档