摘要:事件循环了解了在引擎中是如何工作了之后,来看下如何使用异步回调函数来避免代码。从回调函数被放入后秒钟,把移到中。由于事件循环持续地监测调用栈是否已空,此时它一注意到调用栈空了,就调用并创建一个新的调用栈。
听多了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?下边的图也都引用自这篇文章。
截止到目前(原文编写时间:5 July 2014),在各种JavaScript 引擎的实现里边,最出名的当属Google Chrome的V8引擎了,既能在浏览器中使用,也能通过NodeJS在服务器端使用。但究竟JavaScript引擎是干什么用的?其实很简单--它的任务就是遍历应用中的每一行JavaScript代码,并且一次执行一行,意味着JavaScript是单线程的。这里最大的影响是:如果在JavaScript代码中有地方会占用大量的时间,那后面的代码都会被block住。
那么JavaScript引擎怎么知道如何一次处理一行JavaScript代码?它使用的是一个调用栈call stack。你可以把调用栈比作电梯--第一个进电梯的会最后一个出电梯,最后进电梯的会最先出。
看个栗子:
/* Within main.js */ var firstFunction = function () { console.log("I"m first!"); }; var secondFunction = function () { firstFunction(); console.log("I"m second!"); }; secondFunction(); /* Results: * => I"m first! * => I"m second! */
下边是调用栈的情况:
Main.js 执行
调用secondFunction
调用secondFunction引起调用firstFunction
执行firstFunction,输出“I"m first!”,接着由于firstFunction执行完毕,firstFunction会从调用栈中弹出。
secondFunction继续执行,输出“I"m second!”。接着由于secondFunction执行完毕,secondFunction从调用栈中弹出。
最后,main.js执行完毕,也从栈中弹出。
了解了call stack在JavaScript引擎中是如何工作了之后,来看下如何使用异步回调函数来避免blocking 代码。(译者注:回调函数有多种实现方式,最常见的有:在函数中使用函数作用参数etc。)setTimeout就是使用的回调函数。看个栗子:
/* Within main.js */ var firstFunction = function () { console.log("I"m first!"); }; var secondFunction = function () { setTimeout(firstFunction, 5000); console.log("I"m second!"); }; secondFunction(); /* Results: * => I"m second! * (And 5 seconds later) * => I"m first! */
下边模拟调用栈(在上个栗子的基础上我们这次推前点)
...
secondFunction调用setTimeout,setTimeout入栈:
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。
一旦回调函数加入到Event表中,代码不会被block住,浏览器不会等待5秒之后再继续处理接下去的代码,相反,浏览器继续执行secondFunction的下一行代码,console.log。
在background,Event Table会持续地监测是否有事件触发,将函数移到Event Queue中。在这个栗子中,secondFunction执行完毕,接着main.js也执行完毕。
从回调函数被放入Event Table后5秒钟,Event Table把firstFucntion移到Event Queue中。
由于事件循环持续地监测调用栈是否已空,此时它一注意到调用栈空了,就调用firstFunction并创建一个新的调用栈。
一旦firstFunction执行完毕,调用栈空了,Event Table里也没有注册函数,Event Queue也为空。
虽然这样的解释掩盖了实际JavaScript引擎、Event Table、Event Queue和Event Loop的具体实现细节,但是对于大部分人来说,我们只需要对JavaScript执行异步函数时会发生什么有个大概的了解即可。
(译到此)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/80310.html
摘要:译文事件循环机制之宏任务微任务原文标题这是一篇谷歌大神文章,写得非常精彩。为什么会出现这样打印顺序呢要理解这些你首先需要对事件循环机制处理宏任务和微任务的方式有了解。 译文:JS事件循环机制(event loop)之宏任务、微任务 原文标题:《Tasks, microtasks, queues and schedules》 这是一篇谷歌大神文章,写得非常精彩。译者想借这次翻译深入学习一...
摘要:如果当前没有事件也没有定时器事件,则返回。相关资料关于的架构及设计思路的事件讨论了使用线程池异步运行代码。下一篇初窥事件机制的实现二中定时器的实现 在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力;在Node.js中,事件驱动模型则是其高并发能力的基础。 学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事...
摘要:阶段有两个主要功能也会执行时间定时器到达期望时间的回调函数执行事件循环列表里的函数当进入阶段并且没有其余的定时器,那么如果事件循环列表不为空,则迭代同步的执行队列中的函数。如果没有,则等待回调函数进入队列并立即执行。 Event Loop 本文以 Node.js 为例,讲解 Event Loop 在 Node.js 的实现,原文,JavaScript 中的实现大同小异。 什么是 Eve...
摘要:的宿主最开始本身就是浏览器,处理用户的交互事件。既然是单线程的,那就意味着任务需要排队,只有前一个任务执行完毕,下一个任务才能开始,于是就有了任务队列。事件循环有两种用于浏览上下文的事件循环和用于的事件循环。 最近看到Event Loop这个词出现的频率有点高,于是查阅各方资料在此记录一下。 先不说概念,我们来看段代码: console.log(script start); setT...
摘要:浏览器与的异同,以及部分机制有人对部分迷惑,本身构造函数是同步的,是异步。浏览器的的已全部分析完成,过程中引用阮一峰博客,知乎,部分文章内容,侵删。 浏览器与NodeJS的EventLoop异同,以及部分机制 PS:有人对promise部分迷惑,Promise本身构造函数是同步的,.then是异步。---- 2018/7/6 22:35修改 javascript 是一门单线程的脚本...
阅读 2521·2021-10-11 10:58
阅读 962·2019-08-29 13:58
阅读 1630·2019-08-26 13:32
阅读 797·2019-08-26 10:40
阅读 3215·2019-08-26 10:18
阅读 1740·2019-08-23 14:18
阅读 1082·2019-08-23 10:54
阅读 416·2019-08-22 18:39