对于新接触js语言的人来说,最令人困惑的大概就是事件循环机制了。最开始这也困惑了我好久,花了我几个月时间通过书本,打代码,查阅资料不停地渐进地理解他。接下来我想要和大家分享一下,虽然可能有些许错误的地方,希望大家不吝赐教,感谢感谢。

 这是所涉及的知识点:

  • 观察者模式
  • js的事件循环机制
    • js事件循环机制优缺点及与多线程的比较

观察者模式

 js的事件循环机制是基于观察者模式的,而跟观察者模式相对应的是轮询,我们先来说说轮询的原理。

 我们将轮询映射在现实世界中即为:B不停到A的房间观察房间里是否有人,从而知道A是否回来。

 但显然,这是效率极低的,我们回到代码层面上。B线程使用while(true){观察A的房间,当A在房间内时退出循环}来做到轮询。但是,这样B线程就被堵塞住了,除非退出该循环,否则无法执行接下来的同步代码及异步代码。这对于单线程语言是完全无法接受的,所以我们来看看观察者模式,他是否会堵塞线程。

 同样的,我们来将观察者模式映射到现实世界中:B在自己房间做自己的事情,不再不停地到A的房间看他是否回来,而是当A回到自己房间时,打电话通知B他回来了,B再去房间找A玩。

 该模式最大的优势就是:B可以在等待A回房间的期间,做自己的事情。回到代码层面上,使用观察者模式后,B线程不再被堵塞,A回到房间的信息不再需要B通过循环来同步地监听,而是A用消息传给B线程,B再根据这个消息来执行当A回到房间后应该执行的操作。

 其实当理解了观察者模式的大体流程就已经能够理解js的事件循环机制了。但了解得深入些也没有坏处。接下来我们来用js代码来模拟出一个简易的观察者模式。

代码如下:

var b = {
process_a:mes=>{
console.log('刚刚A发了 %s 的信息,所以我知道A回来了,我该去他房间找他玩了。',mes)
}
} function A(b){
var mes_a = '我是A,我回来了'
b.process_a(mes_a)
} A(b)

 结果如下:

如果大家对同步,异步,堵塞,非堵塞的概念有不理解的地方的话,可以看我的 同步,异步,堵塞,非堵塞,并发 辨析。


事件循环机制

 事件循环机制的核心就是观察者模式。我先给大家描述一遍程序执行的流程。

  1. js程序进入线程,函数入栈,当遇到同步代码的时候就顺序执行,遇到异步代码时,把异步任务抛给WebAPIs执行,然后继续执行接下来的同步代码,直到栈为空。(如若大家对函数栈不了解的话可以看下我的 栈,堆辨析及使用)
  2. 在步骤1进行的同时,WebAPIs执行异步任务,当执行完一个异步任务就将其对应的回调函数放入任务队列(Callback Queue)中等待。
    • WebAPIs是由C++实现的浏览器创建的线程,处理诸如DOM事件,http请求,定时器等异步任务。
  3. 当执行栈为空时,从Callback Queue中取出队列头放入执行栈中,回到第一步。

 给大家一个我画的图,方便理解。

 不过大家可能会疑惑,事件循环机制跟观察者模式哪有什么关系?其实是这样的,在第2步中我写道

当执行完一个异步任务就将其对应的回调函数放入任务队列(Callback Queue)中。

 但我们是如何判断这个异步任务执行完了呢——观察者模式。任务队列是观察者,WebAPIs是被观察者,观察者要求被观察者当发生执行完异步任务这一事件时,通知他执行完了,并将该事件对应的回调函数传过来。

js事件循环机制优缺点及与多线程的比较

 通过事件循环机制,我们就可以实现代码的异步,从而不会堵塞线程。

 通过这一特性,

  1. js在IO上有着卓越的表现,因为IO操作不再会堵塞住线程。
  2. 可以做到高并发。稍微解释一下为什么能够高并发——当同时有多个任务要执行,js将他一一排列起来,然后按顺序执行,这样cpu就不会因为同时要处理的工作太多而负载过大。

 朴灵在《深入浅出nodeJS》中说道:

石器时代:同步。青铜时代:复制线程。白银时代:多线程。黄金时代:事件驱动。

 不过我不敢说事件驱动就是比多线程好,但他确实没有多线程的这些恼人的缺陷。

  1. 如果有大量的线程,会影响性能,因为操作系统需要在线程之间不停进行上下文切换。
  2. 通常数据是多个线程共享的,需要上锁,同时又要防止出现死锁现象。
  3. IO会堵塞住一个线程。

 但同时的,js也有他的缺陷。

  1. 不适合cpu密集型。也解释一下——如一段代码需要非常大量的计算量,以至于他长时间地占着线程,这就堵塞了,后继的同步代码及异步代码都无法执行。不过,html5推出了web worker,可以有效地解决这一缺陷,在本章不表,后面我会专门写一篇文章来讲他。
  2. 只能使用一个线程,无法充分利用计算机的多核cpu。
  3. 可靠性低,一旦一个环节崩溃则整个程序全部崩溃。

 没有一项技术是绝对完美的,但我们要清楚他的优缺点及原因,从而能够充分利用其优点,同时规避其缺点甚至通过自己的方式解决其缺点。


参考资料

  1. Advantages and Disadvantages of a Multithreaded/Multicontexted Application: https://docs.oracle.com/cd/E13203_01/tuxedo/tux71/html/pgthr5.htm
  2. https://www.hostreview.com/blog/160311-the-pros-and-cons-of-using-nodejs: https://www.hostreview.com/blog/160311-the-pros-and-cons-of-using-nodejs
  3. 理解事件循环与任务队列:https://www.jianshu.com/p/e865c3a7ba10

js事件循环机制辨析的更多相关文章

  1. JS 事件循环机制 - 任务队列、web API、JS主线程的相互协同

    一.JS单线程.异步.同步概念 从上一篇说明vue nextTick的文章中,多次出现“事件循环”这个名词,简单说明了事件循环的步骤,以便理解nextTick的运行时机,这篇文章将更为详细的分析下事件 ...

  2. js 事件循环机制 EventLoop

    js 的非阻塞I/O  就是由事件循环机制实现的 众所周知  js是单线程的 也就是上一个任务完成后才能开始新的任务 那js碰到ajxa和定时器.promise这些异步任务怎么办那?这时候就出现了事件 ...

  3. Node.js 事件循环机制

    Node.js 采用事件驱动和异步 I/O 的方式,实现了一个单线程.高并发的 JavaScript 运行时环境,而单线程就意味着同一时间只能做一件事,那么 Node.js 如何通过单线程来实现高并发 ...

  4. js事件循环机制 (Event Loop)

    一.JavaScript是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决 ...

  5. js事件循环机制(Event Loop)

    javascript从诞生之日起就是一门  单线程的  非阻塞的  脚本语言,单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务,非阻塞靠的就是 event lo ...

  6. js事件循环机制

    本文参考链接:https://www.jianshu.com/p/cf47bc0bf2ab 一.先搞懂两个东西:堆和栈 栈由操作系统自动分配释放,用于存放函数的参数值.局部变量等一些基本的数据类型,其 ...

  7. JS:事件循环机制、调用栈以及任务队列

    点击查看原文 写在前面 js里的事件循环机制十分有趣.从很多面试题也可以看出来,考察简单的setTimeout也就是考察这个机制的. 在之前,我只是简单地认为由于函数执行很快,setTimeout执行 ...

  8. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

    javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...

  9. JS JavaScript事件循环机制

    区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...

随机推荐

  1. WPF 列表开启虚拟化的方式

    正确开启虚拟化的方式 列表如ListBox,ListView,TreeView,GridView等,开启虚拟化 ScrollViewer设置CanContentScroll=True 直接在模板中,设 ...

  2. JDBC知识详解

    一.相关概念 1.什么是JDBC JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它 ...

  3. 发现了一个非常棒的pyqt5的例子集

    发现了一个非常棒的pyqt5的例子集 https://github.com/892768447/PyQt 各种各样的PyQt测试和例子 [Python3.4.4 or Python3.5][PyQt5 ...

  4. 浅谈.Net异步编程的前世今生----APM篇

    前言 在.Net程序开发过程中,我们经常会遇到如下场景: 编写WinForm程序客户端,需要查询数据库获取数据,于是我们根据需求写好了代码后,点击查询,发现界面卡死,无法响应.经过调试,发现查询数据库 ...

  5. Adobe Photoshop CC 2019 for Mac v20.0.4 中文版安装教程

    全新Adobe Photoshop CC 2019 mac特别版终于上线了,简称ps cc 2019,Adobe Photoshop CC 2019 for Mac v20.0.4 中文版安装教程分享 ...

  6. Java 学习笔记 Junit4单元测试使用

    Junit使用 1.导入Junit包 到官网下载个Junit4.12.jar文件,放在lib目录 或者在类的空白处打@Test,之后按下alt+enter,选择添加Junit4依赖 之后就会弹出一个窗 ...

  7. 如何让div中的table水平居中

    <div style="text-align:center"> <table border="1" cellpadding="3&q ...

  8. 一、Activity的生命周期和启动模式

    1.Activity的生命周期 1.1.典型情况下的生命周期 在有用户参与的情况下,Activity所经过的生命周期的改变. Activity会经历如下生命周期: onCreate-onRestart ...

  9. 一条SQL生成数据字典

    有个字典表并定期维护,对DBA和开发很重要,终于把他们整合在一起了,看有没问题? 一条SQL生成数据字典,包含所有OPEN用户.表名.字段名.字段序号.字段属性.默认值.是否非空.字段意思.主键标识. ...

  10. Windows-删除Windows Server backup卷影副本

    现有环境中有一台Windows Server做过定期备份计划,时间太久未做清理操作,收到磁盘报警邮件后需要及时释放该空间,具体操作步骤如下: 当前备份计划信息如下: 清理步骤如下: 1.以管理身份运行 ...