Javascript并发模型和事件循环

JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程, javascript的并发是单线程的。

Javascript 中有个重要一块,Event Loop,能把单线程的 JavaScript 使出 多线程的感觉。

"Event Loop是一个程序结构,用于等待和发送消息和事件。(a programming construct that waits for and dispatches events or messages in a program.)"

 

简单的说,就是在程序中(不一定是浏览器)中跑两个线程,一个负责程序本身的运行,作为主线程; 另一个负责主线程与其他线程的的通信,被称为“Event Loop 线程" 。  每当遇到异步的 setTimeOut ,setInterval 这些异步任务,交给 EventLoop 线程,然后自己往后运行,等到主线程运行完后,再去 Event Loop 线程拿结果。

这种模型人称 "asynchronous" 或 "non-blocking" 模行。 

我简单的画了一个 javascript 的执行图,我们通过图,逐步分析.

函数调用时所用的执行环境栈

当js方法被调用时,会进入一个执行环境(execution context),如果有另外一个方法被调用了(或者自身递归调用),会新建一个新的执行环境,并且代码的执行会进入到这个新的执行环境.函数调用返回的时候重新回到原来的执行环境. 由此,代码执行的过程便形成了一个执行环境栈,江湖人称 "stack";

执行环境

execution context 是一个由ECMA定义的抽象的概念,所有的javascript代码都是在 execution context 执行环境中执行的.

全局执行环境是最外层的一个执行环境.在Web浏览器中,全局执行环境认为是window对象.因此所有全局变量和函数都是作为window对象的属性和方法创建的.

全局的代码(inline中执行的代码,通常包括js文件,html页面,加载的)在全局执行环境中执行.每个方法调用都有一个与之关联的执行环境.

某个执行环境中的所有代码执行完毕后,该执行环境被销毁,保存在其中的所有变量和函数定义也随之销毁. 全局执行环境直到页面关闭时才被销毁.

每个函数都有自己的执行环境,当执行流进入一个函数时,函数的执行环境就会被推入环境栈中. 而在函数执行之后,栈

将其环境栈弹出,把控制权返回给之前的执行环境.js中的执行流正是由这个方便的机制的控制着.

当代码在一个执行环境中执行时,会创建变量对象的一个作用域链(scope chain).

作用域链的用途,确保当前执行环境能有序(不明白就接着看)的访问所能获取的变量和函数.

作用域链的前端,始终都是当前执行的代码所在的执行环境的变量对象.

即当前作用域没有,外层作用域兜着.

执行环境被创建时会有次序的进行一些工作.

  1. 首先,在方法的执行环境中,Activation 活动对象被创建.活动对象另有一套实现机制.可以认为是对象,但又很特殊,没有prototype,不能在代码中直接引用到.
  2. 下一步,在方法调用创建执行环境的时候,会创建 argument 对象(类数组对象,含有传进来的参数,length,callee),活动对象中会有一个"argument"同名属性来引用这个argument对象.
  3. 再下一步,执行环境会被指定一个作用域.作用域由承载对象的列表(或链)组成.当代码在一个执行环境中执行,会创建变量对象的一个作用域链(scope chain).作用域链的前端,始终都是当前执行的代码所在执行环境的变量对象(和上面提到的 Activation 活动对象是一个对象). 如果这个环境是函数(javascript 环境只有函数和全局环境这两种), 则将其活动对象作为变量对象使用,活动对象在最开始时只包含一个arguments对象.

作用域链中下一个变量对象来自当前代码的外层环境.以此类推,直到到达最外层的全局执行环境,这样便构成了一条从底到上的作用域链.全局执行环境的变量对象始终都是作用域链的最后一个对象.

标示符解析是沿着作用域链一级一级的搜索标示符的过程.搜索过程始终都是从作用域链的最前端开始,然后主逐级向后回溯.

当进入执行环境

当进入执行环境(代码即将但仍未执行时),变量对象也就是活动对象已经包含了以下这些属性:

  1. 函数的所有形参,由名称和对应值组成变量对象的属性.
  2. 执行环境所在函数内部的所有子函数声明,由名称和对应值(函数对象 function object)组成变量对象的属性.如果变量对象内已存在同名属性,那么会被替换所有的变量声明.
  3. 由名称和对应值(undefined)组成变量对象的属性,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性.

需要说明的是,每个执行环境都有this,this的值取决于调用者和所执行代码的类型,this值是在进入执行环境时就已经确定的. 取值与执行环境相关联,并且在执行环境运行期间是不能被修改的.

this 执行上下文中的一个属性.

在全局代码中,this始终是全局对象本身.

在通常的函数调用中,this是由函数的调用者提供的,即被调用函数的父执行环境提供的.this值取决于函数调用的方式.

堆是一个对象互联的网络。用数学术语说就是“图”。图由节点及其之间的边构成。节点和边都是可被标记的:节点(对象)用对象构造器的名称标记,边则由属性名称标记。

从一个对象到另一个的边序列被叫做路径(path)。通常我们只对那些不重复经过同一节点两次的简单路径(simple path)感兴趣。

我们把垃圾收集器根节点到某个指定对象的路径叫做retaining path。如果不存在这样的路径,则该对象被称作无法达到的(unreachable),应在垃圾收集过程中被处置。

队列

在web浏览器中,当事件发生时如果该事件有相应的监听器,则该消息会被及时的加进消息队列,如果没有监听器,该事件会被丢失.

javascript运行时伴随一个待处理的消息(也就是任务)队列,每个消息都关联了相关的处理函数,当函数的执行栈为空时,即当前没有正在执行的函数,那么,队列会从中挑出一个去处理.处理过程包括调用相关的函数(不用担心处理函数的作用域问题,因为在javascript中,作用域是词法化作用域,是方法在定义的时候已经确定的,与调用无关.作用域链创建早于方法调用,得益于此,我们方能使用闭包),处理完成后,如果栈为空,则再次尝试从队列中挑选可处理的事件或任务. 从中可以很容易窥探到 setInterval,setTimeout 是怎么进行异步执行的了.

这,就是事件循环,event loop.

总结

通过上面的分析,javascript是不存在并发的,单线程何谈并发? 这只是说说了非阻塞.

Javascript并发模型和事件循环的更多相关文章

  1. JavaScript Concurrency model and Event Loop 并发模型和事件循环机制

    原文地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop JavaScript 有一个基于 event loop 的 ...

  2. javascript的event loop事件循环

    javascript的event loop事件循环 这是今天一个朋友发给我的一个面试题, 感觉还挺有意思的, 写个博客以供分享 先看看这个面试题目: 观察下面的代码,写出输出结果 console.lo ...

  3. JavaScript单线程和浏览器事件循环简述

    JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...

  4. JavaScript之JS单线程|事件循环|事件队列|执行栈

    本博文基于知乎"JavaScript作用域问题?"一问,而引起了对JavaScript事件循环和单线程等概念与实践上的研究.深入理解. 一.概念 0.关键词:JavaScript单 ...

  5. How Javascript works (Javascript工作原理) (四) 事件循环及异步编程的出现和 5 种更好的 async/await 编程方式

    个人总结: 1.讲解了JS引擎,webAPI与event loop合作的机制. 2.setTimeout是把事件推送给Web API去处理,当时间到了之后才把setTimeout中的事件推入调用栈. ...

  6. JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  7. JavaScript事件循环(Event Loop)机制

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

  8. JavaScript:彻底理解同步、异步和事件循环(Event Loop) (转)

    原文出处:https://segmentfault.com/a/1190000004322358 一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS ...

  9. 【转向Javascript系列】从setTimeout说事件循环模型

    本文首发在alloyteam团队博客,链接地址http://www.alloyteam.com/2015/10/turning-to-javascript-series-from-settimeout ...

随机推荐

  1. 安装 Ruby, Rails 运行环境 常见的错误

    安装部署ruby on rails 的环境时并不是想的那么顺利 这个是我遇到的问题及解决的方式 参考安装博客: (1) https://ruby-china.org/wiki/install_ruby ...

  2. OC初步 (一)

    OC完全兼容C, 代码后缀名一般习惯用 *.m 或 *.mm,按惯例从 "Hello,World!" 开始,我们编写一个 test.mm 文件如下: #import <Fou ...

  3. python基础知识(二)

    以下内容,作为python基础知识的补充,主要涉及基础数据类型的创建及特性,以及新数据类型Bytes类型的引入介绍

  4. MVVM开发模式简单实例MVVM Demo

    本文主要是翻译Rachel Lim的一篇有关MVVM模式介绍的博文 A Simple MVVM Example 并具体给出了一个简单的Demo(原文是以WPF开发的,对于我自己添加或修改的一部分会用红 ...

  5. 项目里面的某个.m文件无法使用

    - 检查:Build Phases -> Compile Sources

  6. 微信公众平台可通过UnionID机制在多公众号间帐号互通

    微信公众平台越来越注重开发者的反馈信息了,这不,微信开放平台提供了UnionID机制,通过获取用户基本信息接口,开发者可通过OpenID来获取用户基本信息,而如果开发者拥有多个公众号,可使用以下办法通 ...

  7. screen 常用命令

    screen -r <id | name>  # 进入 screen C-a c # ctrl+a + c , 新建screen窗口 C-a A # ctrl+a + A, 命名scree ...

  8. "转" CXF+JAXB处理复杂数据

    CXF简单数据类型以及类(JavaBean)都提供了较好的支持. 但是对于一些复杂类型(集合或者Map的嵌套)的处理时,就需要我们进行“”人工干预“.在网上找了一些文章,其中这篇写的最为详细,再次备注 ...

  9. Hide JSP error icons in Eclipse

    down voteaccepted Can can either configure this at workspace level or overwrite at web project level ...

  10. Nginx上传文件返回413的解决

    通过http上传文件时返回403 Request Entity Too Large错误时,原因是默认设置的允许上传文件太小,默认是2M,如果上传文件大小大于2M时,那么就会返回413的错误,修改ngi ...