对于怎么理解js中Event Loop,你能够看这篇文章

javascript中event loop是什么

声明

源文档地址javascript

介绍

如何你跟我同样的话,那么你必定会爱上javascript!虽然它不是一种比较完美的编程语言,可是严格地说,还有其它比javascript更完美的语言来设计web吗?因此请忽视javascript的缺陷吧。我喜欢web工做,而javascript使得我能够用其来创建applications,从而跟web上的用户联系起来!java

可是若是你深究javascript——你会发现,它的一些内部概念你须要花费许多时间才能真正理解!其中一个概念就是Event Loop,可能一个在web开发中工做了几年的开发人员也没有真正理解其含义和工做原理,无论怎样,我但愿经过这篇文章,能带给你一些启发:什么是event loop?其实它并非那么难以理解的!node

浏览器中的Javascript

咱们一般所说的javascript,都是指浏览器端使用的javascript——由于咱们写的javascript代码大多数是用在客户端的!无论怎样,理解这些概念和技术是很是重要的:一、Javascript Engine(好比 Chrome's V8),二、Web API(如 DOM),三、Event Loop 和 Event Quene。git

你可能看过上面列举的这些概念以后,你可能会这样想:“好复杂呀!”,确实是这样的!可是经过这篇文章待会儿你会发现,其实它们并无那么复杂!github

在介绍event loop以前,咱们须要对javascript engine作一个简单的理解来明白它是作什么的!web

Javascript Engine

有几种不一样的js引擎,可是最流行的一个当属谷歌的V8了(它并不只仅在浏览器环境中使用,经过nodejs,它也在服务器端使用)。可是js引擎的工做究竟是什么呢?其实,引擎的工做很是简单——它会遍历咱们写的全部js代码,而后一个一个的执行它们。也就是说咱们的js是单线程的,单线程很差的地方就是,若是你同步执行了一段很长时间的代码的话,那么这段代码后面的逻辑会被阻塞从而等待好久才能执行。同门一般都不想写阻塞的代码——特别是在浏览器中,设想若是你点击了一个按钮以后去执行了一个很长时间的阻塞代码,这会致使你的页面的其它交互效果会暂停,严重影响用户体验!编程

那么js引擎是怎么知道一个一个的处理代码呢?其实它使用了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! */复制代码

首先,js引擎会维护一个调用栈序列的:app

  • main.js第一次执行的时候,调用栈序列是这样的:

  • 当调用secondFunction的时候,调用栈序列:

  • 咱们调用secondFunction致使firstFunction被调用,因此此时序列是这样的:

  • 当执行完firstFunction,会打印“I'm first!”,而后在其内部就没有其它代码执行了,因此调用栈序列须要把firstFunction移除,因此此时序列是这样的:

  • 一样,secondFunction打印完“I'm second!”以后,在其内部也没有其它代码须要执行了,因此会移除其,因此此时序列是这样的:

  • 最后,当main.js中没有其它代码须要执行的时候,那么匿名函数也会被从调用栈中移除,从而这样:

好了,说了半天,什么是Event Loop?

到如今,咱们已经知道js引擎的调用栈的原理了,那么咱们回到刚才所讨论的阻塞代码的问题上,咱们都知道应该避免写阻塞代码!庆幸的是,js提供了一种机制来实现非阻塞:异步回调函数!咱们又接触了一个概念,是否是觉得这个概念很牛逼呢?其实并非,异步回调函数跟你写过的其它的普通的函数同样的!只不过它不是同步执行的,若是你熟悉的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的回调函数放到(在这个例子中就是firstFunction)Event Table中。你能够把Event Table理解成为一个注册机构,调用栈会告诉Event Table去注册一个特别的函数,当特定的事件发生的时候去执行它,当特定的事件发生时,Event Table只是简单的把这个函数移动到Event Quene里面,Event Quene只是一个放置函数即将执行的暂存区,最后由Event Quene把函数移动到调用栈中。

你可能会问,Event Quene何时知道把回调函数放回到调用栈中呢?好,js引擎听从一个简单的规则:浏览器中存在一个进程会不断地去检查调用栈是否为空,同时,不管任什么时候候只要调用栈为空,它会检查Event Quene是否有待执行的函数队列!若是调用栈为空,那么它会把Event Quene队列里面的第一个函数放到调用栈中,若是Event Quene为空的话,那么这个进程将会无限期地来回地进行检查,好吧——咱们描述的这个就是所谓的Event Loop!

  • 如今回到咱们的例子,执行的setTimeout函数的时候,咱们向Event Table里面注册了一个回调函数(在这个例子中是firstFunction),而且延迟5秒可执行!调用栈序列此时是这样的:

  • 咱们运行代码的时候会发现,咱们的代码并无等待5秒以后才打印“I'm second!”,而是天然地执行了下一行代码,此时代码序列是这样的:

  • 在背后,Event Table会不断的监视跟回调函数相关的时候那个事件(这个例子中为等待5秒)是否发生,从而把回调函数移动到可执行的Event Quene序列里面。与此同时,secondFunction和main.js中匿名函数都执行完了,因此调用栈序列此时是这样的:

  • 通过5秒以后,event table会移动firstFunction到event quene里面:

  • 同时event loop不断的监视当前调用栈是否为空,若是是,则把event quene序列里面的第一个回调函数放到调用栈(新的,不一样于刚才的调用栈,刚才的已经没有了)里面。因此此时调用栈序列是这样的:

  • 当firstFunction执行完成以后,浏览器会返回一个状态:调用栈会空,event table没有任何事件可监听,同时Event Quene队列为空!最后是这样的:

相关文章
相关标签/搜索