深入了解Javascript的事件循环机制

深入了解JavaScript的事件循环机制

JavaScript 是一门单线程语言,这意味着在 JavaScript 中,代码是按顺序执行的,只有前一个任务执行完成后,才会执行下一个任务。但是 JavaScript 中有许多异步操作,如定时器、事件监听器、网络请求等,这些操作不会阻塞代码的执行,可以同时执行。那么在 JavaScript 中是如何处理异步操作的呢?这就要涉及到 JavaScript 的事件循环机制。

事件循环机制的基本概念

JavaScript 中的事件循环(Event Loop)机制是基于消息队列(Message Queue)实现的。消息队列是一种先进先出的数据结构,保存着要执行的异步任务或事件。

当代码执行到一个异步操作时,会将该操作的回调函数添加到事件循环的消息队列中。当主线程执行完成所有同步任务后,会不断地从消息队列中取出最先进入队列的任务,执行它们的回调函数。这个不断循环取出任务的过程就被称为事件循环。

可以把消息队列中的任务分为两类:宏任务(Macro Task)、微任务(Micro Task)。宏任务包括定时器(setTimeout、setInterval)、DOM 事件、网络请求等,主线程执行完所有同步任务后,会按照一定的顺序执行所有宏任务的回调函数。微任务包括 Promise、MutationObserver 等,它们的回调函数会在当前任务执行完成后立即执行。

事件循环机制的执行过程

事件循环机制的执行过程可以用以下伪代码来表示:

while (true) {
  // 执行当前的宏任务
  let task = queue.getTask();
  if (task) {
    task();
  }

  // 执行当前宏任务的微任务
  while (microTaskQueue.length > 0) {
    let microTask = microTaskQueue.shift();
    microTask();
  }
}

其中 queue 表示宏任务队列,microTaskQueue 表示微任务队列。在循环中,会执行当前宏任务中的所有同步任务以及第一个异步任务,之后进入下一轮事件循环。当前宏任务执行完成后,会执行当前宏任务中所有的微任务。

示例一:setTimeout

下面来看一个定时器的例子:

console.log('code start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise');
});

console.log('code end');

输出的结果是:

code start
code end
Promise
setTimeout

先输出 code startcode end,然后执行微任务队列中的 Promise,最后输出 setTimeout。这是因为定时器的回调函数会先放入宏任务队列,其回调函数会在执行完当前宏任务以及微任务后执行,而 Promise 中的回调函数会先放入微任务队列中,优先级比定时器的回调函数高。因此,先输出 Promise

示例二:事件监听器

再来看一个事件监听器的例子:

<button id="btn">click me</button>
console.log('code start');

document.getElementById('btn').addEventListener('click', () => {
  console.log('button clicked');
});

console.log('code end');

点击按钮后,在控制台输出 button clicked。这是因为事件监听器的回调函数会先放入宏任务队列中,等到事件触发后,才会执行回调函数。在这个例子中,所有同步任务执行完成后,先执行微任务队列中的任务,之后进入事件循环,等待事件的触发。

结语

JavaScript 的事件循环机制是理解 JavaScript 异步编程非常重要的一环,只有深入了解其工作原理,才能写出高效且容错的代码。在编写 Web 应用或 Node.js 服务端程序时,要时刻注意事件循环机制的执行顺序,以免造成意料之外的错误。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入了解Javascript的事件循环机制 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • js获取浏览器基本信息大全

    获取浏览器基本信息是前端开发中比较常用的一个需求。通过 JavaScript 可以获取浏览器的类型、版本号、操作系统类型等信息。下面就来详细讲解一下如何获取浏览器基本信息。 获取浏览器类型和版本号 可以使用 navigator.userAgent 获取当前浏览器的 UserAgent 字符串,然后通过正则表达式匹配出浏览器类型和版本号。 // 获取浏览器类型…

    JavaScript 2023年6月11日
    00
  • Javascript中的prototype与继承

    JavaScript的原型(prototype)是一种机制,它允许对象继承另一个对象的属性和方法。在这种机制下,对象可以通过其原型链访问到其他对象的属性和方法。在本篇文章中,我们将探讨 JavaScript 中的 prototype 和继承。 原型(prototype) 每个Javascript对象(除了null和undefined)都有一个内部的属性[[P…

    JavaScript 2023年6月10日
    00
  • 改变状态栏文字的js代码

    要通过JS代码来改变网页的状态栏文字,可以使用document.title属性。这个属性可以读取和设置当前网页的标题,同时一些浏览器也会将其作为状态栏文字显示。 下面是两个针对页面不同状态,使用JS代码改变状态栏文字的例子。 例子1:在鼠标hover链接时,将链接地址作为状态栏文字显示 在这个例子中,我们可以利用JS来改变链接的状态栏文字。当用户将鼠标指向链…

    JavaScript 2023年6月11日
    00
  • 简单易用的倒计时js代码

    下面是一份简单易用的倒计时js代码的攻略: 1. 先导入jQuery库 <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> 2. 创建一个HTML元素作为计数器容器 可以把它放在合适的地方,如下所示: <div id=&quo…

    JavaScript 2023年5月27日
    00
  • JS Object构造函数之Object.freeze

    Object.freeze()是JavaScript中的一个内置方法,它会冻结一个对象,使对象成为不可修改的。一旦一个对象被冻结,任何的属性、值、方法等都将不能被修改、添加、删除或重新赋值。 使用Object.freeze()方法能有效地保护Javascript对象的数据,避免意外修改,从而提高代码的可维护性和安全性。 Object.freeze()方法的用…

    JavaScript 2023年5月28日
    00
  • 正则表达式创建方式的区别及编写简单的正则方式(js学习总结)

    让我来详细讲解一下“正则表达式创建方式的区别及编写简单的正则方式”的攻略。 区别 首先,我们需要了解正则表达式创建方式的区别。常见的正则表达式创建方式有以下三种: 字面量方式:使用斜杠(/)将正则表达式包裹起来,例如:/abc/ 构造函数方式:使用new RegExp()构造函数来创建正则表达式对象,例如:new RegExp(‘abc’) 工厂函数方式:使…

    JavaScript 2023年6月10日
    00
  • 同步异步动态引入js文件的几种方法总结

    同步、异步、动态引入js文件的几种方法总结 在Web开发中,为了更好地优化页面性能,我们需要对js文件的引入做些优化处理。其中包括同步引入、异步引入和动态引入js文件。下面将介绍这几种引入js文件的方法以及他们的使用场景。 同步引入 同步引入指的是在HTML文件中,直接使用<script>标签引入js文件。使用同步引入的时候,浏览器会在下载js文…

    JavaScript 2023年5月27日
    00
  • js 中的switch表达式使用示例

    当我们需要根据不同的条件执行不同的代码块时,使用 switch 语句是一种比较方便的选择。在 JavaScript 中,switch 表达式使用示例如下: switch 语句的结构 switch (表达式) { case 标签1: 执行代码块 1; break; case 标签2: 执行代码块 2; break; … default: 执行代码块 n; …

    JavaScript 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部