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是怎么运行的,这样你可以可以使 ...
随机推荐
- RestEasy 3.x 系列之三:jsonp
跨域请求解决方法(JSONP, CORS)提到解决跨域可以使用jsonp,RestEasy自带jsonp的拦截器 一.RestEasy的文档如下: If you're using Jackson, R ...
- 反编译软件jad
http://blog.csdn.net/small____fish/article/details/7687261 这是原网址,挺全的. 官网上下载jad,再把jad.exe 复制到javahome ...
- python logging bydate
#!/usr/bin/env python #_*_coding:utf-8_*_ # vim : set expandtab ts=4 sw=4 sts=4 tw=100 : import logg ...
- 常用软件:Bugzilla的搭建(转)
1.安装依赖包yum -y install php perl httpd mod_ssl mysql-server mysql-devel mysql php-mysql gcc mod_perl-d ...
- inotify +rsync进行实时同步
1.安装rpm -ivh http://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpmyum -y install ino ...
- 基于服务(Web Service)的文件管理Winform程序实现
1. 描述 面向服务的体系结构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现 ...
- 重装系统后,delphi7打开报错
delphi7运行不正常的提示unable to rename'c:\program files\Borland\delphi7\Bin\delphi32.$$$'to'c:\program file ...
- JSP的基本语法:
JSP文件有5类元素:注释,模版,脚本,指令,行为 下面我就和大家分别唠唠,这5个玩意到底是啥玩意! 一.注释(我feel有三种): html注释:<!--……--> 显式注释,即客户端 ...
- OAF_文件系列10_实现OAF将数据资料导出Excel到本地JXL(案例)
20150729 Created By BaoXinjian
- SpringMVC学习系列(11) 之 表单标签
本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...