javascript中event loop是什么

声明

源文档地址

介绍

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

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

浏览器中的Javascript

我们通常所说的javascript,都是指浏览器端使用的javascript——因为我们写的javascript代码大多数是用在客户端的!不管怎样,理解这些概念和技术是非常重要的:1、Javascript Engine(比如 Chrome's V8),2、Web API(如 DOM),3、Event Loop 和 Event Quene。

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

在介绍event loop之前,我们需要对javascript engine做一个简单的理解来明白它是做什么的!

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引擎会维护一个调用栈序列的:

  • 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队列为空!最后是这样的:

对于怎么理解js中Event Loop,你可以看这篇文章相关推荐

  1. 彻底理解js中this

    相关博文:http://blog.csdn.net/libin_1/article/details/49996815 彻底理解js中this的指向,不必硬背. 首先必须要说的是,this的指向在函数定 ...

  2. 彻底理解js中this的指向

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  3. 理解JS中的this的指向

    原文地址:https://www.cnblogs.com/pssp/p/5216085.html#1 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到 ...

  4. 理解js中this的指向

    彻底理解js中this的指向 JavaScript 的 this 指向问题深度解析 转载于:https://www.cnblogs.com/jeacy/p/6509616.html

  5. 深入理解Js中的this

    深入理解Js中的this JavaScript作用域为静态作用域static scope,但是在Js中的this却是一个例外,this的指向问题就类似于动态作用域,其并不关心函数和作用域是如何声明以及 ...

  6. js原型和原型链_理解JS中的原型和原型链

    导读:JavaScript中(JS)的原型和原型链是web前端开发面试中经常被问到的问题:同时,如果我们能很好的理解JS中的原型和原型链,对于控制台输出的很多信息我们也能更好的理解,而原型链也是实现继 ...

  7. 理解JS中的声明式与命令式

    理解JS中的声明式与命令式? 声明式编程 :告诉机器你想要的是什么    让机器想出去做 优缺点 : 声明式减少了可变量(Immutable Variable)的声明,程序更为安全,   代码更加简洁 ...

  8. 理解js中的面向对象

    目录 前言: 一点疑问: 1.封装 2.继承 原型链的查找机制 不容易理解的点: ----重点在最后---- 前言: js是一门面向对象的语言,但是又没有类的概念,虽然后来加入了class,但也就是个 ...

  9. 斗鱼html5插件音画不同步,音画不同步在直播中怎么解决?看这篇文章就够了!...

    原标题:音画不同步在直播中怎么解决?看这篇文章就够了! 什么是音画不同步? 很容易判断,就是画面和声音不匹配. 为什么会音画不同步? 首先我们要明白一个概念,虽然人的肉眼很容易辨别音画是否同步的,但是 ...

最新文章

  1. 【算法精讲】集成分类与随机森林
  2. linux云服务终端提示符显示-bash-4.2#解决方法
  3. 枚举算法称硬币C语言,【算法系列之枚举】称硬币
  4. 【工具】FTP软件FileZilla下载和连接服务器
  5. php如何做水仙花数,使用PHP实现水仙花数及各种特殊有趣数的输出
  6. Intellij IDEA导入JAVA项目并启动(哈哈哈,天天都有人问)
  7. PHP 5 将于年底停止更新,六成用户将面临安全风险
  8. TFLite模型文件转C语言文件
  9. iOS设备是否越狱的判断代码
  10. java持续集成soapui_接口自动化测试持续集成--Soapui接口测试
  11. 盘点那些年,被Oracle收购的公司
  12. SQL-Server笔记
  13. UVA 11572 唯一的雪花 Unique Snowflakes
  14. 服务器上可以重装操作系统吗,服务器操作系统可以重装
  15. AForge学习笔记(5):AForge.Imaging(上)
  16. linux源码中,.org 0x2000,ENTRY(pg1)表示的是什么意思?org是什么意思,ENTRY是什么意思啊?
  17. LeetCode 342. 4的幂 附带《Effective C++》pdf版下载
  18. 小傻蛋的妹妹跟随小甲鱼学习Python的第九节009
  19. 联想MIIX520笔记本电脑屏幕亮度无法调节问题
  20. 两年融资 280 亿,美国的新造车势力又行了?

热门文章

  1. StringBuffer跟StringBuilder以及HashMap跟HashTable
  2. 关于Ubuntu下apt的一些用法及和yum的比较
  3. Wijmo 更优美的jQuery UI部件集:在安全站点使用Wijmo控件
  4. 配置Voice vlan
  5. MoFi 路由器10个后门还剩4个未修复
  6. 开源内容管理系统 Joomla 数据遭泄露
  7. Java开发技术大杂烩(三)之电商项目优化、rabbitmq、Git、OSI、VIM、Intellj IDEA、HTTP、JS、Java...
  8. 树莓派与笔记本用远程桌面连接(Xrdp远程桌面服务)
  9. Spring中的AOP(8)
  10. 代码重构之旅(一) 项目结构