原文地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

JavaScript 有一个基于 event loop 的并发模型,这个模型和其他如 Java 和 C 语言的模型是不同的。

Runtime concepts 运行时概念

下面是一个可视化的模型展示,现代 JavaScript 引擎实现并着重优化了这个模型。

Stack 栈

函数从一个调用栈中执行,这个栈由多个调用栈帧组成

  1. function foo(b) {
  2. var a = ;
  3. return a + b + ;
  4. }
  5.  
  6. function bar(x) {
  7. var y = ;
  8. return foo(x * y);
  9. }
  10.  
  11. console.log(bar()); //returns 42

调用 bar 时,第一个调用帧被创建,这个帧包含 bar 的参数和局部变量,在 bar 内部调用 foo,第二个调用帧被创建,然后入栈,放在第一个调用帧的上面。

当 foo 执行完成以后,栈顶的帧就会出栈。当 bar 也执行完成之后,栈为空。

Heap 堆

对象被分配到一个堆中,堆这个名字就象征着一大块没有结构的内存区域。

Queue 队列

一个 JavaScript 运行时有一个消息队列(message queue),这是一个待处理消息列表,每个消息有相应的函数会被调用来处理这个消息。

在 event loop 的某个时刻,运行时开始处理队列中的消息,从最早的那一个开始。这个消息将被移出队列,对应的函数会被调用,并将这个消息作为参数。

同样和前面一样,这个函数调用也会给这个函数产生一个调用栈帧。

函数执行的过程会一直持续到调用栈再次为空,然后 event loop 会继续处理消息队列中的下一个消息 (如果有的话)

Event loop 事件循环

事件循环的实现原理类似于下面的伪代码:

  1. while (queue.waitForMessage()) {
  2. queue.processNextMessage();
  3. }

如果当前没有事件消息,queue.waitForMessage() 会同步地等待

Run-to-completion 执行到完成

在其它消息被处理之前,当前的消息会完全处理结束。这在你分析自己的代码时有非常好的特性,比如当一个函数执行时,它不会被提前阻止,在其它代码运行之前会完整地执行(这些代码可能会改变此函数操作的数据)。这个 C 语言不同,例如,当一个线程中的一个函数运行,它可能会被中止,因为运行时要去处理其它线程中的另外一些代码。

这个模型的一个缺点就是,如果一个消息需要过长的处理时间,web 应用将无法处理其它如点击或者鼠标滚动事件。浏览器会弹出对话框“程序需要过长事件无法运行”的对话框来处理这种消息。一个好的实践是将消息处理时长减少,如果可以,将一个消息分成多个消息。

Adding message 添加消息

在 web 浏览器中,只要一个事件发生并且有一个事件监听绑定到这个事件,就会添加消息到队列中。如果没有监听到,事件就丢失了。

函数 setTimeout 有两个参数,一个将添加到队列中的消息,一个代表延迟的时间值(毫秒,默认为0)。这个时间代表添加到队列前的最少等待时间。

如果队列中没有其它消息,则这个消息将在延迟之后立即被处理。然而,如果有其它消息,setTimeout 的消息还要等待其它消息处理。所以第二个参数仅仅代表最少时间,并不保证确切的时间长度。

下面是一个例子

  1. const s = new Date().getSeconds();
  2.  
  3. setTimeout(function() {
  4. // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  5. console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
  6. }, 500);
  7.  
  8. while(true) {
  9. if(new Date().getSeconds() - s >= 2) {
  10. console.log("Good, looped for 2 seconds");
  11. break;
  12. }
  13. }

Zero delays 零延时

延时设置为 0 并不表示回调函数会立即执行,是否执行取决于队列中等待的任务的数量。

在下面的例子中,cb1 是最后执行的,因为它要等待队列前面的任务执行完毕。

  1. (function() {
  2.  
  3. console.log('this is the start');
  4.  
  5. setTimeout(function cb() {
  6. console.log('this is a msg from call back');
  7. });
  8.  
  9. console.log('this is just a message');
  10.  
  11. setTimeout(function cb1() {
  12. console.log('this is a msg from call back1');
  13. }, 0);
  14.  
  15. console.log('this is the end');
  16.  
  17. })();
  18.  
  19. // "this is the start"
  20. // "this is just a message"
  21. // "this is the end"
  22. // note that function return, which is undefined, happens here
  23. // "this is a msg from call back"
  24. // "this is a msg from call back1"

几个运行时之间通信

一个 web worker 或者 一个跨域的 iframe 都要自己的栈、堆和消息队列。

两个不同的运行时只能通过 postMessage 方法进行通信。

另外一个运行时如果监听 message 时间,就可以添加消息到自己的队列。

Never blocking 非阻塞

时间循环机制的一个非常有趣的特性的就是永远不会阻塞。

处理 I/O 事件通常都通过事件和回调函数执行。当应用在等待一个数据库查询或者 XHR 请求的结果时,可以同时处理其它事情比如用户输入。

遗留问题也是存在的,比如 alert 或者 同步的XHR,不过好的实践是避免使用它们。

JavaScript Concurrency model and Event Loop 并发模型和事件循环机制的更多相关文章

  1. Javascript并发模型和事件循环

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

  2. 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)

    JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...

  3. JavaScript 运行机制:Event事件循环机制

    JavaScript Event事件循环机制 JS是单线程的,浏览器只分配一个主线程给JS.一次只能执行一个任务,当前任务执行完后在可以执行下一个任务.任务多时,就会形成任务队列排队等待执行.但是非常 ...

  4. javascript事件循环机制 浅尝手记

    引入 众所周知Javascript是一个单线程的机制,虽然可以依托多线程的浏览器实现页面如何实现页面复杂的渲染.事件响应,但仍不会改变其单线程的本质:所以对于js的事件循环机制的了解是一个前端人员的必 ...

  5. 深入理解JavaScript事件循环机制

    前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...

  6. 对javascript EventLoop事件循环机制不一样的理解

    前置知识点: 浏览器原理,浏览器内核5种线程及协作,JS引擎单线程设计推荐阅读: 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 [FE]浏览器渲染引擎「内核」 js异步编程,Promise ...

  7. 【运行机制】 JavaScript的事件循环机制总结 eventLoop

    0.从个例子开始 //code-01 console.log(1) setTimeout(() => { console.log(2); }); console.log(3); 稍微有点前端经验 ...

  8. JavaScript中的事件循环机制跟函数柯里化

    一.事件循环机制的理解 test();//按秒输出5个5 function test() { for (var i = 0; i < 5; i++) { setTimeout(() => ...

  9. JS JavaScript事件循环机制

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

随机推荐

  1. 第六节:WebApi的部署方式(自托管)

    一. 简单说明 开篇就介绍过WebApi和MVC相比,其中优势之一就是WebApi可以不依赖于IIS部署,可以自托管,当然这里指的是 .Net FrameWork 下的 WebApi 和 MVC 相比 ...

  2. [Android] Android 类似今日头条顶部的TabLayout 滑动标签栏 效果

    APP市场中大多数新闻App都有导航菜单,导航菜单是一组标签的集合,在新闻客户端中,每个标签标示一个新闻类别,对应下面ViewPager控件的一个分页面,今日头条, 网易新闻等. 本文主要讲的是用:T ...

  3. [物理学与PDEs]第1章第9节 Darwin 模型 9.2 Maxwell 方程组的一个定解问题

    设 $\Omega$ 为一有界区域, 外部为理想导体 $(\sigma=+\infty)$, 则 $\Omega$ 中电磁场满足 Maxwell 方程组 $$\beex \bea \ve\cfrac{ ...

  4. Educational Codeforces Round 52 (Rated for Div. 2)

    题目链接 A. Vasya and Chocolate 题意 已知钱,价格,赠送规则求最多获得巧克力数 思路常规算即可 代码 #include <bits/stdc++.h> #defin ...

  5. Coursera, Big Data 3, Integration and Processing (week 5)

    Week 5, Big Data Analytics using Spark     Programing in Spark   Spark Core: Programming in Spark us ...

  6. js打印WEB页面内容代码大全

    第一种方法:指定不打印区域 使用CSS,定义一个.noprint的class,将不打印的内容放入这个class内. 详细如下: <style media=print type="tex ...

  7. 【洛谷P2660烤鸡】

    题目背景 猪猪hanke得到了一只鸡 题目描述 猪猪Hanke特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke吃鸡很特别,为什么特别呢?因为他有10种配料(芥末.孜然等),每种配料可以放1—3克, ...

  8. Bmob后端云学习(未完)

    Bmob后端云学习 BaaS(后端即服务:Backend as a Service)公司为移动应用开发者提供整合云后端的边界服务. 这种服务的一个代表就是Bmob后端云,BAT和亚马逊 ,都有这类产品 ...

  9. Alpha 事后诸葛亮(团队)

    前言 事后诸葛亮?作业名真的不好听,下一届还要沿用吗? 队名:小白吃 通向hjj博客的任意门 思考总结 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? ...

  10. Java_运算符

    目录 一.算术运算符 二.关系运算符 三.位运算符 四.赋值运算符 五.条件运算符 六.instanceof 运算符 七.逻辑运算符 一.算术运算符 加 减 乘 除 取余 自增 自减(+ - * / ...