JavaScript Concurrency model and Event Loop 并发模型和事件循环机制
原文地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
JavaScript 有一个基于 event loop 的并发模型,这个模型和其他如 Java 和 C 语言的模型是不同的。
Runtime concepts 运行时概念
下面是一个可视化的模型展示,现代 JavaScript 引擎实现并着重优化了这个模型。

Stack 栈
函数从一个调用栈中执行,这个栈由多个调用栈帧组成
function foo(b) {
var a = ;
return a + b + ;
}
function bar(x) {
var y = ;
return foo(x * y);
}
console.log(bar()); //returns 42
调用 bar 时,第一个调用帧被创建,这个帧包含 bar 的参数和局部变量,在 bar 内部调用 foo,第二个调用帧被创建,然后入栈,放在第一个调用帧的上面。
当 foo 执行完成以后,栈顶的帧就会出栈。当 bar 也执行完成之后,栈为空。
Heap 堆
对象被分配到一个堆中,堆这个名字就象征着一大块没有结构的内存区域。
Queue 队列
一个 JavaScript 运行时有一个消息队列(message queue),这是一个待处理消息列表,每个消息有相应的函数会被调用来处理这个消息。
在 event loop 的某个时刻,运行时开始处理队列中的消息,从最早的那一个开始。这个消息将被移出队列,对应的函数会被调用,并将这个消息作为参数。
同样和前面一样,这个函数调用也会给这个函数产生一个调用栈帧。
函数执行的过程会一直持续到调用栈再次为空,然后 event loop 会继续处理消息队列中的下一个消息 (如果有的话)
Event loop 事件循环
事件循环的实现原理类似于下面的伪代码:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
如果当前没有事件消息,queue.waitForMessage() 会同步地等待
Run-to-completion 执行到完成
在其它消息被处理之前,当前的消息会完全处理结束。这在你分析自己的代码时有非常好的特性,比如当一个函数执行时,它不会被提前阻止,在其它代码运行之前会完整地执行(这些代码可能会改变此函数操作的数据)。这个 C 语言不同,例如,当一个线程中的一个函数运行,它可能会被中止,因为运行时要去处理其它线程中的另外一些代码。
这个模型的一个缺点就是,如果一个消息需要过长的处理时间,web 应用将无法处理其它如点击或者鼠标滚动事件。浏览器会弹出对话框“程序需要过长事件无法运行”的对话框来处理这种消息。一个好的实践是将消息处理时长减少,如果可以,将一个消息分成多个消息。
Adding message 添加消息
在 web 浏览器中,只要一个事件发生并且有一个事件监听绑定到这个事件,就会添加消息到队列中。如果没有监听到,事件就丢失了。
函数 setTimeout 有两个参数,一个将添加到队列中的消息,一个代表延迟的时间值(毫秒,默认为0)。这个时间代表添加到队列前的最少等待时间。
如果队列中没有其它消息,则这个消息将在延迟之后立即被处理。然而,如果有其它消息,setTimeout 的消息还要等待其它消息处理。所以第二个参数仅仅代表最少时间,并不保证确切的时间长度。
下面是一个例子
const s = new Date().getSeconds();
setTimeout(function() {
// prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
}, 500);
while(true) {
if(new Date().getSeconds() - s >= 2) {
console.log("Good, looped for 2 seconds");
break;
}
}
Zero delays 零延时
延时设置为 0 并不表示回调函数会立即执行,是否执行取决于队列中等待的任务的数量。
在下面的例子中,cb1 是最后执行的,因为它要等待队列前面的任务执行完毕。
(function() {
console.log('this is the start');
setTimeout(function cb() {
console.log('this is a msg from call back');
});
console.log('this is just a message');
setTimeout(function cb1() {
console.log('this is a msg from call back1');
}, 0);
console.log('this is the end');
})();
// "this is the start"
// "this is just a message"
// "this is the end"
// note that function return, which is undefined, happens here
// "this is a msg from call back"
// "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 并发模型和事件循环机制的更多相关文章
- Javascript并发模型和事件循环
Javascript并发模型和事件循环 JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程, javascript的并发是单线程的. Javas ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)
JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...
- JavaScript 运行机制:Event事件循环机制
JavaScript Event事件循环机制 JS是单线程的,浏览器只分配一个主线程给JS.一次只能执行一个任务,当前任务执行完后在可以执行下一个任务.任务多时,就会形成任务队列排队等待执行.但是非常 ...
- javascript事件循环机制 浅尝手记
引入 众所周知Javascript是一个单线程的机制,虽然可以依托多线程的浏览器实现页面如何实现页面复杂的渲染.事件响应,但仍不会改变其单线程的本质:所以对于js的事件循环机制的了解是一个前端人员的必 ...
- 深入理解JavaScript事件循环机制
前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...
- 对javascript EventLoop事件循环机制不一样的理解
前置知识点: 浏览器原理,浏览器内核5种线程及协作,JS引擎单线程设计推荐阅读: 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 [FE]浏览器渲染引擎「内核」 js异步编程,Promise ...
- 【运行机制】 JavaScript的事件循环机制总结 eventLoop
0.从个例子开始 //code-01 console.log(1) setTimeout(() => { console.log(2); }); console.log(3); 稍微有点前端经验 ...
- JavaScript中的事件循环机制跟函数柯里化
一.事件循环机制的理解 test();//按秒输出5个5 function test() { for (var i = 0; i < 5; i++) { setTimeout(() => ...
- JS JavaScript事件循环机制
区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...
随机推荐
- [物理学与PDEs]第2章习题6 有旋的 Navier-Stokes 方程组
试证明: 由 Navier-Stokes 方程组描述的流体运动一般总是有旋的, 即若 $\rot{\bf u}={\bf 0}$, 则 Navier-Stokes 方程组 (3. 4)-(3. 5) ...
- win10安装VMware v14.1.1.28517
一.下载 VMware v14.1.1.28517 下载地址(包含安装说明):http://www.downza.cn/soft/74728.html 二.VMware Workstation 14 ...
- [Harbor]Harbor简要介绍
前一段时间写过一篇文章:[Kubernetes]CentOS7下搭建Harbor仓库,只是知道了如何搭建,但是对于背后的整体架构还不是太清楚,这篇文章就来讲讲. 默认情况下,Harbor运行起来后有如 ...
- POJ 2318 TOYS (叉积+二分)
题目: Description Calculate the number of toys that land in each bin of a partitioned toy box. Mom and ...
- 关于 min_25 筛的入门以及复杂度证明
min_25 筛是由 min_25 大佬使用后普遍推广的一种新型算法,这个算法能在 \(O({n^{3\over 4}\over log~ n})\) 的复杂度内解决所有的积性函数前缀和求解问题(个人 ...
- 推荐一款中国风React组件
最近看这个中国风的组件在掘金也火了一段时间,看了有几天了,也体验了下,感觉还不错,所以准备来安利下 项目地址:https://github.com/zhui-team/zhui 使用手册请参考:htt ...
- C++设计模式——装饰模式
前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这 ...
- C#+EntityFramework编程方式详细之Database First
Database First “Database First”模式即“数据库优先”,其实Database First 与Model First 很类似,只不过一个是有数据可一个是创建数据库,具体的操作 ...
- LinkedList阅读
package java.util; import java.util.function.Consumer; public class LinkedList<E> extends Abst ...
- 四.property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则 # 例一:BMI指数(bmi是计算而 ...