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(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...
随机推荐
- Love Me,Love My Dog
Love me, love my dog. 爱屋及乌. 出处<尚书大传•大战>:“爱人者,兼其屋上之乌.” 活学活用:love first love 初恋 unrequited [one- ...
- 给Myeclipse配置tomcat服务器
1.安装好Tomcat 7.x服务器 2.window->perference,在搜索框中搜索Tomcat: 3.将MyEclipse自带的Tomcat及其他的Tomcat服务器禁用: 4.启用 ...
- hadoop与hbase对应的支持版本
官网信息:http://hbase.apache.org/book.html#java JDK的对应关系: 用jdk1.8+hadoop2.7.4/hadoop2.7.6+zookeeper3.4.1 ...
- JQuery EasyUI 之 messager基本使用
♦ 基本语法:$.messager.alert ( title , msg , icon , fn ): 其中,icon有四种设置:"error"."info" ...
- C# 微信开发-----微信会员卡(三)激活会员卡
在会员领取了会员卡之后需要做 一个跳转性激活,模式请看下图: 在创建会员卡的时候需要配置下这个参数的值: memberActivate.aspx页面代码如下: <%@ Page Language ...
- js——图片懒加载
<img class="js-lazy-image centered" src="./img/dog-running.svg" width="4 ...
- vue路由守卫(全局守卫)
router.beforeEach((to,from,next)=>{}) 回调函数中的参数, to:进入到哪个路由去, from:从哪个路由离开, next:函数,决定是否展示你要看到的路由页 ...
- MySQL批量更新字段url链接中的域名
1. 首先进行数据库备份 2. SQL语句 UPDATE 表名 SET 字段 = REPLACE(字段, '待更新的内容','替换值'); eg: UPDATE 98k_images SET url ...
- apache安装软负载的配置说明
安装Apache:yum -y install httpd 首先要查看apache的安装版本 命令:httpd –v 第一种: 若安装是2.2版本,则把复制 mod_wl_22.so和mod_wl.s ...
- springboot集成mybatis源码分析-启动加载mybatis过程(二)
1.springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplication中的@EnableAutoConfiguration 2.EnableAuto ...