如何玩转JavaScript的事件循环

简介:

听多了JavaScript单线程,异步,V8,便会很想去知道JavaScript是如何利用单线程来实现所谓的异步的。我参考了一些文章,了解到一个很重要的词汇:事件循环(Event Loop)。在这些文章中,有:

  • 阮一峰老师的JavaScript 运行机制详解:再谈Event Loop
  • Philip Roberts的What the heck is the event loop anyway?
  • Erin Swenson-Healey的The JavaScript Event Loop: Explained等。

这些文章都讲得非常好,让我对Event Loop的机制有了大概的了解。

异步在JavaScript的重要性,也意味着理解Event Loop的必要性,不然怎么敢轻易使用setTimeout和setInterval这些咧。

这里我还是通过翻译一篇文章来解释Event Loop,原文点这里Willson Mock:What is the JavaScript Event Loop?下边的图也都引用自这篇文章。

JavaScript Engine:JavaScript 引擎

截止到目前(原文编写时间:5 July 2014),在各种JavaScript 引擎的实现里边,最出名的当属Google Chrome的V8引擎了,既能在浏览器中使用,也能通过NodeJS在服务器端使用。但究竟JavaScript引擎是干什么用的?其实很简单--它的任务就是遍历应用中的每一行JavaScript代码,并且一次执行一行,意味着JavaScript是单线程的。这里最大的影响是:如果在JavaScript代码中有地方会占用大量的时间,那后面的代码都会被block住。

那么JavaScript引擎怎么知道如何一次处理一行JavaScript代码?它使用的是一个调用栈call stack。你可以把调用栈比作电梯--第一个进电梯的会最后一个出电梯,最后进电梯的会最先出。

看个栗子:


 
 
  1. /* Within main.js */ 
  2.  
  3. var firstFunction = function () {   
  4.   console.log("I'm first!"); 
  5. }; 
  6.  
  7. var secondFunction = function () {   
  8.   firstFunction(); 
  9.   console.log("I'm second!"); 
  10. }; 
  11.  
  12. secondFunction(); 
  13.  
  14. /* Results: 
  15.  * => I'm first
  16.  * => I'm second
  17.  */  

下边是调用栈的情况:

1.Main.js 执行

2.调用secondFunction

3.调用secondFunction引起调用firstFunction

4.执行firstFunction,输出“I'm first!”,接着由于firstFunction执行完毕,firstFunction会从调用栈中弹出。

5.secondFunction继续执行,输出“I'm second!”。接着由于secondFunction执行完毕,secondFunction从调用栈中弹出。

6.最后,main.js执行完毕,也从栈中弹出。

Event Loop:事件循环

了解了call stack在JavaScript引擎中是如何工作了之后,来看下如何使用异步回调函数来避免blocking 代码。(译者注:回调函数有多种实现方式,最常见的有:在函数中使用函数作用参数etc。)setTimeout就是使用的回调函数。看个栗子:


 
 
  1. /* Within main.js */ 
  2.  
  3. var firstFunction = function () {   
  4.  console.log("I'm first!"); 
  5. }; 
  6.  
  7. var secondFunction = function () {   
  8.  setTimeout(firstFunction, 5000); 
  9.  console.log("I'm second!"); 
  10. }; 
  11.  
  12. secondFunction(); 
  13.  
  14. /* Results: 
  15.  * => I'm second
  16.  * (And 5 seconds later) 
  17.  * => I'm first
  18.  */  

下边模拟调用栈(在上个栗子的基础上我们这次推前点)

1....

2.secondFunction调用setTimeout,setTimeout入栈:

3.setTimeout执行后,浏览器会把setTimeout的回调函数(在这个栗子中是firstFunction)放到Event Table中。Event Table 就是个注册站:调用栈让Event Table注册一个函数,该函数会在5秒之后被调用。当指定的事情发生时,Event Table会将这个函数移到Event Queue。Event Queue其实就是个缓冲区域,这里的函数等着被调用并移到调用栈。

问题来了,什么时候函数会从Event Queue移到调用栈咧?JavaScript引擎依据一条规则:有一个monitoring process(不知翻译成啥好)会持续不断地检查调用栈是否为空,一旦为空,它会检查Event Queue里边是否有等待被调用的函数。如果存在,它就会调用这个Queue中第一个函数并将其移到调用栈中。如果Event Queue为空,那么这个monitoring process会继续不定期的检查。这一整个过程就是Event Loop。

4.一旦回调函数加入到Event表中,代码不会被block住,浏览器不会等待5秒之后再继续处理接下去的代码,相反,浏览器继续执行secondFunction的下一行代码,console.log。

5.在background,Event Table会持续地监测是否有事件触发,将函数移到Event Queue中。在这个栗子中,secondFunction执行完毕,接着main.js也执行完毕。

6.从回调函数被放入Event Table后5秒钟,Event Table把firstFucntion移到Event Queue中。

7.由于事件循环持续地监测调用栈是否已空,此时它一注意到调用栈空了,就调用firstFunction并创建一个新的调用栈。

8.一旦firstFunction执行完毕,调用栈空了,Event Table里也没有注册函数,Event Queue也为空。

总结

虽然这样的解释掩盖了实际JavaScript引擎、Event Table、Event Queue和Event Loop的具体实现细节,但是对于大部分人来说,我们只需要对JavaScript执行异步函数时会发生什么有个大概的了解即可。


作者:zhoushx3

来源:51CTO

相关文章
|
5天前
|
存储 JavaScript 前端开发
深入理解JavaScript中的事件循环(Event Loop):机制与实现
【10月更文挑战第12天】深入理解JavaScript中的事件循环(Event Loop):机制与实现
22 3
|
29天前
|
JavaScript 前端开发 API
详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务
该文章详细讲解了队列数据结构在前端开发中的应用,并深入探讨了JavaScript的事件循环机制,区分了宏任务和微任务的执行顺序及其对前端性能的影响。
|
5天前
|
前端开发 JavaScript
深入理解JavaScript中的事件循环(Event Loop):从原理到实践
【10月更文挑战第12天】 深入理解JavaScript中的事件循环(Event Loop):从原理到实践
15 1
|
8天前
|
Web App开发 JavaScript 前端开发
深入理解Node.js事件循环和异步编程模型
【10月更文挑战第9天】在JavaScript和Node.js中,事件循环和异步编程是实现高性能并发处理的基石。本文通过浅显易懂的语言和实际代码示例,带你一探究竟,了解事件循环的工作原理及其对Node.js异步编程的影响。从基础概念到实际应用,我们将一步步解锁Node.js背后的魔法,让你的后端开发技能更上一层楼!
|
13天前
|
设计模式 JavaScript API
Node.js 事件循环
10月更文挑战第3天
26 0
Node.js 事件循环
|
26天前
|
JavaScript 调度 数据库
深入浅出:Node.js中的异步编程与事件循环
【9月更文挑战第30天】在Node.js的世界里,理解异步编程和事件循环是掌握其核心的关键。本文将通过浅显易懂的语言和实际代码示例,带你探索Node.js如何处理并发请求,以及它是如何在幕后巧妙地调度任务的。我们将一起了解事件循环的各个阶段,并学会如何编写高效的异步代码,让你的应用程序运行得更加流畅。
50 10
|
25天前
|
JavaScript 前端开发 开发者
深入理解Node.js中的事件循环和异步编程
【9月更文挑战第31天】本文旨在揭示Node.js背后的强大动力——事件循环机制,并探讨其如何支撑起整个异步编程模型。我们将深入浅出地分析事件循环的工作原理,以及它如何影响应用程序的性能和稳定性。通过直观的例子,我们会展示如何在实际应用中利用事件循环来构建高性能、响应迅速的应用。此外,我们还会讨论如何避免常见的陷阱,确保代码既优雅又高效。无论你是Node.js的新手还是经验丰富的开发者,本篇文章都将为你提供宝贵的洞察和实用技巧。
56 6
|
1月前
|
JavaScript 开发者
深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第57天】本文将带你走进Node.js的事件循环机制,通过浅显易懂的语言和实例代码,揭示其背后的工作原理。我们将一起探索如何高效利用事件循环进行异步编程,提升后端应用的性能和响应速度。无论你是Node.js新手还是有一定经验的开发者,这篇文章都能给你带来新的启发和思考。
|
1月前
|
JavaScript API 数据库
深入理解Node.js事件循环及其在后端开发中的应用
【9月更文挑战第3天】本文将深入浅出地介绍Node.js的事件循环机制,探讨其非阻塞I/O模型和如何在后端开发中利用这一特性来处理高并发请求。通过实际的代码示例,我们将看到如何有效地使用异步操作来优化应用性能。文章旨在为读者揭示Node.js在后端开发中的核心优势和应用场景,帮助开发者更好地理解和运用事件循环来构建高性能的后端服务。
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的图像识别技术深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第27天】本文将介绍深度学习中的图像识别技术,包括其原理、应用领域及未来发展。我们将探讨如何通过神经网络实现图像识别,并分析其在医疗、交通等领域的应用。最后,我们将展望图像识别技术的发展前景。