javascript运行模式:并发模型 与Event Loop
看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和【朴灵评注】的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日后再看做个回顾。
MDN上有张图很形象,
function f(b){
var a = 12;
return a+b+35;
}
function g(x){
var m = 4;
return f(m*x);
}
g(21);
上面函数调g用形成了一个 frames 的栈。调用g的时候,创建了第一个 frame,包含了 g 的参数和局部变量。当 g 调用 f 的时候,第二个 frame 就被创建、并置于第一个 frame 之上,包含了 f 的参数和局部变量。当f返回时,最上层的 frame 就出栈了(剩下 g 函数调用的 frame)。当g返回的时候,栈就空了。
队列
一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。当栈为空时,从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数(以及因此而创建的一个初始栈结构)。当栈再次为空的时候,也就意味着消息处理结束。
在浏览器里,当一个事件出现且有一个事件监听器被绑定时,消息会被随时添加。如果没有事件监听器,事件会丢失。所以点击一个附带点击事件处理函数的元素会添加一个消息。其它事件亦然。
绝不阻塞
一个很有趣的事件循环 (event loop) 模型特性在于,Javascript 跟其它语言不同,它永不阻塞。处理 I/O (input/output) 通常由事件或者回调函数进行实现。所以当一个应用正等待 IndexedDB 的查询的返回或者一个 XHR 的请求返回时,它仍然可以处理其它事情例如用户输入。
例外是存在的,如 alert 或者同步 XHR,但避免它们被认为是最佳实践。注意的是,例外的例外也是存在的(但通常是实现错误而非其它原因)。
Event Loop
举例node.js的Event Loop
朴灵的解释
- 【完全不是不同的任务分配给不同的线程。只有磁盘IO操作才用到了线程池(unix)。】
- 【Node中,磁盘I/O的异步操作步骤如下:】
- 【将调用封装成中间对象,交给event loop,然后直接返回】
- 【中间对象会被丢进线程池,等待执行】
- 【执行完成后,会将数据放进事件队列中,形成事件】
- 【循环执行,处理事件。拿到事件的关联函数(callback)和数据,将其执行】
- 【然后下一个事件,继续循环】
使用事件驱动的系统中,必然有非常非常多的事件。如果事件都产生,都要主循环去处理,必然会导致主线程繁忙。那对于应用层的代码而言,肯定有很多不关心的事件(比如只关心点击事件,不关心定时器事件)。这会导致一定浪费。
【事实上,不是所有的事件都放置在一个队列里。】
【不同的事件,放置在不同的队列。】
【当我们没有使用定时器时,则完全不用关心定时器事件这个队列】
【当我们进行定时器调用时,首先会设置一个定时器watcher。事件循环的过程中,会去调用该 watcher,检查它的事件队列上是否产生事件(比对时间的方式)】
【当我们进行磁盘IO的时候,则首先设置一个io watcher,磁盘IO完成后,会在该io watcher的事件队列上添加一个事件。事件循环的过程中从该watcher上处理事件。处理完已有的事件后,处理下一个watcher】
【检查完所有watcher后,进入下一轮检查】
【对某类事件不关心时,则没有相关watcher】
定时器
定时器仅仅是在未来的某个时刻将代码添加到代码队列中,执行时机是不能保证的。代码队列按照先进先出的原则在主进程空闲后将队列中的代码交给主线程运行。
在Javascript中没有任何代码是立刻执行的,带一旦进程空闲则尽快执行。例如,当某个按钮被按下时,事件处理函数会被添加到代码队列中。当接收到ajax响应时,回校函数的代码被添加到队列中。而定时器对队列的工作方式是,当特定的事件过去后将代码加入到队列中。设定一个150ms后执行的定时器不代表代码会在150ms之后执行,而是指代码会在150ms后加入到代码队列中。等到主进程空闲时并且该元素位于队列首位,其中的代码便会立即执行,看上去好像是在精确的时间点上执行了。实际上队列中的所有代码都要等到主进程空闲之后才能执行,而不管他们是怎额添加到队列中去的。
(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');
var time= new Date();
while(new Date() - time < 2000) {}
})();
//打印顺序如下:
this is the start
this is just a message
this is the end
//2S之后执行settimeout内容,虽然0秒后执行setTimeout内容,但是主线程代码还没执行完,so等主线程空闲的时候再立即执行setTimeout代码
this is a msg from call back
this is a msg from call back1
当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才能将定时器代码添加到代码队列中。
var original = Date.now();
setInterval(function(){
console.log('run interval', Date.now() - original);
var start = Date.now();
while(Date.now() - start < 350) {};
original = Date.now();
}, 200);
var start = Date.now();
while(Date.now() - start < 300) {};
在使用setInterval时:
- 某些间隔会被跳过
- 多个定时器的代码执行之间的间隔可能会比预期的小(当前的setInterval回调正在执行,后一个添加)
参考:http://www.cnblogs.com/dojo-lzz/p/4606448.html
所以在使用setInterval做动画时要注意两个问题:
不能使用固定步长作为做动画,一定要使用百分比: 开始值 + (目标值 - 开始值) * (Date.now() - 开始时间)/ 时间区间
如果主进程运行时间过长,会出现跳帧的现象。为了避免setInterval的两个缺点,可以使用链式setTimeout():
setTimeout(function(){
//其他处理
setTimeout(arguments.callee, interval);
}, interval);
javascript运行模式:并发模型 与Event Loop的更多相关文章
- JavaScript并发模型与Event Loop (转载)
并发模型可视化描述 model.svg 如上图所示,Javascript执行引擎的主线程运行的时候,产生堆(heap)和栈(stack),程序中代码依次进入栈中等待执行, 若执行时遇到异步方法,该异步 ...
- JavaScript 运行机制详解:Event Loop
参考地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是 ...
- JavaScript 运行机制详解:Event Loop——续
转自:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 五.定时器 除了放置异步任务的事件,"任务队列"还可以放置定时事 ...
- 深入理解 JavaScript 事件循环(一)— event loop
引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...
- js运行机制详解:event loop
总结 阮一峰老师的博客 一.为什么JavaScript是单线程 JavaScript语言的一大特点就是单线程 那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScript ...
- [更新]单线程的JS引擎与 Event Loop
先来思考一个问题,JS 是单线程的还是多线程的?如果是单线程,为什么JavaScript能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO ...
- 从event loop规范探究javaScript异步及浏览器更新渲染时机
异步的思考 event loops隐藏得比较深,很多人对它很陌生.但提起异步,相信每个人都知道.异步背后的“靠山”就是event loops.这里的异步准确的说应该叫浏览器的event loops或者 ...
- JavaScript 事件循环 — event loop
引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...
- 理解Nodejs的Event Loop
Node的“event loop”主要是用来处理高输出量的.这很神奇,这也是为什么node可以在单线程的情况下同时处理很多的后台操作.本文就会集中讲述event loop是怎么运行的,这样你可以可以使 ...
随机推荐
- unity, 调节图片导入尺寸
unity中直接导入高清图,通过max size来调节图片尺寸. 打包的时候通过看editor log或通过插件来监视是否有过大尺寸的图片.
- docker 私有镜像管理工具harbor 安装
因为各种原因,官方的离线安装包下载比较费事,经常不成功,所以通过分部安装解决问题 1. docker yum install libdevmapper* -y -H tcp://0.0.0.0:237 ...
- Businessworks的设计思想
Businessworks的设计思想基于一下三篇ATA: <从Eclipse平台看交易平台化>,强调微内核和扩展机制实现 <Google Guice平台模块化开发的果汁>,讨论 ...
- MySql 存储过程及调用方法
存储过程实例: DELIMITER $$drop procedure if exists ff $$CREATE /*[DEFINER = { user | CURRENT_USER }]*/ PRO ...
- cookie禁用了,session还能用吗?
Cookie与 Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案.但为什么禁用Cookie就不能得到Session ...
- Hadoop总结篇之四---底层通信是怎么做到的
上一篇介绍了一个job的提交过程.期间多次提到通信协议.那么协议是什么? 协议其实就是通信的双方所遵守的一套规范,这套规范规定了通信时传输的数据的固定的格式. 4.1 RPC协议:在hadoop中,我 ...
- 线程优先级抢占实验【RT-Thread学习笔记 3】
同时处于就绪状态的线程,优先级高的先执行. 高优先级就绪时,低优先级任务让出CPU,让高优先级任务先执行. 创建两个任务函数: //线程优先级抢占 void thread1_entry(void *p ...
- OAF_开发系列13_实现OAF通过Vector动态查询设置(案例)
20150715 Created By BaoXinjian
- Python创建cvs文件,包含标签和图片数据
在深度学习或者机器学习的时候,常常需要对数据进行整理和分类,最常见的是通过对数据路径和标签写入 到一个整合的txt或者csv文件中,训练进行读取. #coding=utf-8 #!/usr/bin/ ...
- delphi 串口 关于RS485总线通信协议开发注意事项
http://blog.csdn.net/shjhuang/article/details/9426739 关于RS485总线通信协议开发注意事项 1 前言 近段时间发现我们系统在进行设备 ...