乐闻世界logo
搜索文章和话题
JavaScript为什么需要事件循环Event Loop?对比浏览器执行环境和NodeJS执行环境

JavaScript为什么需要事件循环Event Loop?对比浏览器执行环境和NodeJS执行环境

乐闻的头像
乐闻

2022年08月09日 10:11· 阅读 481

前言

JavaScript 是一门单线程的,非阻塞的,基于事件的编程语言。它是由 ECMAScript(JavaScript 语言核心)和一些浏览器提供的 API (如 DOM,AJAX 等)组成的。

这篇文章将一步步解析JavaScript的核心概念之一:事件循环,它是 JavaScript 运行时的主要组成部分,处理并执行任务,控制 JavaScript 的执行顺序,并允许非阻塞 I/O 操作。

什么是事件循环

事件循环是处理和执行任务的机制,它决定了 JavaScript 应用程序中代码的执行顺序。它提取任务(例如一段 JavaScript 代码或一些浏览器的 API 调用)并将其放入执行队列中。后者是一个存储待处理任务的队列。

为什么需要事件循环

JavaScript 的非阻塞 I/O 模型要求它能在等待异步操作(如网络请求、定时器、用户交互等)的返回结果时还能执行其它代码。事件循环允许 JavaScript 决定在得到这种异步结果时应该执行什么代码。

执行流程

常见的JavaScript执行环境有Node.js 和浏览器,虽然JavaScript 的事件循环是在执行环境中起着相同的作用,但它们的工作方式和处理异步事件的具体机制有一定的区别。

1*FA9NGxNB6-v1oI2qGEtlRQ.png

一、浏览器环境

JavaScript 的事件循环的执行流程如下:

  1. 初始化阶段

    解析并执行初始化代码(例如全局脚本或函数)。

  2. 检查调用栈

    如果调用栈为空,它会转到消息队列。如果不为空,当前堆栈顶部的任务会被弹出并执行。

  3. 消息队列检查

    当调用栈为空,事件循环会查看消息队列中是否有待处理的任务。如果有,那么它会被删除并推到调用栈以供执行。

  4. 等待阶段

    如果调用栈和消息队列都为空,那么事件循环会等待直到一个新的任务添加到消息队列里。

  5. 循环开始

    事件循环会再次检查调用栈,并继续步骤2至步骤4,形成一个无限循环,或者直到全局执行环境关闭(例如,关闭浏览器页面或关闭 node.js 服务器)。

注意:任务可以是任何 JavaScript 代码段。它们可以是由事件(如点击或键盘事件)触发的段落,一段 setTimeout 计时器,或一个来自 AJAX 调用的响应等。

二、NodeJS环境

Node.js使用libuv库来创建和管理事件循环,以下是Node.js的事件循环的执行流程:

  1. timers阶段

    此阶段执行定时器的回调函数。例如:setTimeout 和 setInterval。

  2. pending callbacks阶段

    执行在上一轮循环中少数的系统操作的回调。

  3. idle, prepare阶段

    此阶段是libuv的内部阶段,用于准备下一轮的I/O事件。

  4. poll阶段

    除了设定的回调,其余关闭调用都在此阶段执行,此阶段也会处理新的I/O事件。

  5. check阶段

    在这个阶段调用setImmediate() 设置的回调函数。

  6. close callbacks阶段

    最后,如果有任何close事件,如:socket.on('close'...)等,会在这个阶段调用。

这是一个循环体,所以会不断地在这些阶段之间转换。对于每一个阶段,事件循环都会执行相应的回调,然后进入下一阶段。这就是为什么这个模型被称为事件循环。

总结

以上就是事件循环的基本概念,需要性和执行流程。学习 JavaScript时,理解事件循环机制的重要性不言而喻。透过这篇文章,希望能帮助你更好地理解 JavaScript 代码的运行机制。同样也帮助你更好地理解非阻塞 I/O 和 asynchronous/await 中的“异步”如何在 JavaScript 中工作。

标签: