欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 探索 JavaScript 事件机制(三):事件循环机制

探索 JavaScript 事件机制(三):事件循环机制

2024/10/24 10:46:49 来源:https://blog.csdn.net/m0_37890289/article/details/143201254  浏览:    关键词:探索 JavaScript 事件机制(三):事件循环机制

前言

JavaScript 是一种单线程的编程语言,这意味着它一次只能做一件事。那么,面对大量的任务(如用户点击、网络请求、定时器等),JavaScript 是如何高效地处理的呢?答案就在于它的事件循环机制。今天,我们将通过通俗易懂的讲解,带你探索 JavaScript 的事件循环机制。

什么是事件循环?

事件循环(Event Loop)是 JavaScript 的核心机制之一。它负责执行代码、收集和处理事件,以及执行队列中的子任务。简单来说,事件循环就是 JavaScript 用来处理异步操作的秘密武器。

同步与异步

在深入探讨事件循环之前,我们需要先了解两个重要概念:同步和异步。

  • 同步(Synchronous):任务按顺序执行,一个任务完成后才执行下一个任务。
  • 异步(Asynchronous):任务可以在等待其他任务完成时继续执行,不需要按照顺序来。

举个简单的例子:
同步代码示例:

console.log('1');
console.log('2');
console.log('3');

输出结果是:

1
2
3

异步代码示例:

console.log('1');
setTimeout(() => {console.log('2');
}, 1000);
console.log('3');

输出结果是:

1
3
2

在上面的异步示例中,setTimeout 是一个异步操作,它让 “2” 在 1 秒后输出,而不是立即输出。

事件循环的工作原理

事件循环的核心是一个 “消息队列”(Message Queue)和一个 “调用栈”(Call Stack)。让我们一步步看一下它们是如何配合工作的:

  1. 调用栈:这是一个栈结构,记录了所有正在执行的函数。同步任务会按顺序进入调用栈执行。
  2. 消息队列:这是一个队列结构,存放了所有待处理的异步任务。当调用栈为空时,事件循环会从消息队列中取出第一个任务并将其放入调用栈执行。

事件循环的执行顺序是:先执行完所有的同步任务,再依次处理微任务队列中的任务,最后处理宏任务队列中的任务。
具体步骤如下:

  1. 执行同步任务:所有同步任务进入调用栈,并按顺序执行。
  2. 执行微任务:同步任务执行完毕后,立即执行微任务队列中的所有任务,直到微任务队列为空。
  3. 执行宏任务:微任务执行完毕后,从宏任务队列中取出第一个任务并执行。
  4. 重复以上步骤:直到所有任务(同步任务、微任务、宏任务)都被执行完毕。

宏任务与微任务

在 JavaScript 中,任务可以分为宏任务和微任务。这两类任务在事件循环中有不同的执行顺序和优先级。

宏任务(Macro Task)

宏任务,又称为大任务,包含了一些常见的异步操作,例如:

  • setTimeout
  • setInterval
  • I/O 操作
  • script(整体代码)

微任务(Micro Task)

微任务,又称为小任务,主要包含以下几类:

  • Promise.then回调
  • MutationObserver
  • process.nextTick(Node.js 环境)

深入理解宏任务与微任务

1. 微任务的优先级更高

微任务在每个事件循环的结束时执行,优先级高于宏任务。因此,即使宏任务队列中有任务待处理,微任务也会先行执行完毕。

2. 微任务执行时可以生成新的微任务

在执行微任务时,如果生成了新的微任务,这些新生成的微任务会被立即加入微任务队列,并在当前微任务执行完毕后立即执行。这样,微任务队列会在每次事件循环时被彻底清空。

3. 宏任务可能产生新的宏任务或微任务

宏任务在执行时,可能会产生新的宏任务或微任务。新的宏任务会被加入宏任务队列,等待下一次事件循环。而新的微任务会被立即加入微任务队列,并在当前事件循环中执行。

以下是一个更复杂的示例,帮助你进一步理解:

console.log('Start');setTimeout(() => {console.log('Timeout 1');Promise.resolve().then(() => {console.log('Promise 3');});
}, 0);Promise.resolve().then(() => {console.log('Promise 1');
}).then(() => {console.log('Promise 2');
});console.log('End');

执行顺序分析:

  1. console.log(‘Start’) 立即执行,输出 “Start”。
  2. setTimeout 被调用,将回调函数加入宏任务队列。
  3. Promise.resolve().then(…) 被调用,将回调函数加入微任务队列。
  4. console.log(‘End’) 立即执行,输出 “End”。
  5. 同步任务执行完毕,调用栈为空,开始执行微任务:
  • 执行第一个微任务,输出 “Promise 1”。
  • 执行第二个微任务,输出 “Promise 2”。
  1. 微任务执行完毕,开始执行宏任务:
  • 执行宏任务 setTimeout,输出 “Timeout 1”。
  • 宏任务内部的 Promise.resolve().then(…) 被调用,将回调函数加入微任务队列。
  1. 当前事件循环结束,再次执行微任务:
  • 执行微任务,输出 “Promise 3”。

最终输出顺序是:

Start
End
Promise 1
Promise 2
Timeout 1
Promise 3

总结

事件循环是 JavaScript 处理异步操作的核心机制。它通过调用栈和消息队列配合,使得 JavaScript 即使在单线程的情况下也能高效地处理大量任务。理解事件循环、宏任务和微任务的概念和执行顺序,不仅能帮助我们编写更高效的代码,还能避免很多常见的异步编程陷阱。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com