javascript的并发模型基于事件循环。javascript是一个单线程模型。
此模型的确定:
这个模型的一个缺点在于当一个消息的完成耗时过长,网络应用无法处理用户的交互如点击或者滚动。
运行时概念
可视化描述
栈
函数调用形成了一个栈帧。
function foo(b) {
var a = 10;
return a + b + 11;
}
function bar(x) {
var y = 3;
return foo(x * y);
}
console.log(bar(7));
当调用 bar 时,创建了第一个帧 ,帧中包含了 bar 的参数和局部变量。当 bar 调用 foo 时,第二个帧就被创建,并被压到第一个帧之上,帧中包含了 foo 的参数和局部变量。当 foo 返回时,最上层的帧就被弹出栈(剩下 bar 函数的调用帧 )。当 bar 返回的时候,栈就空了。
堆
对象被分派在堆中。
队列
一个javascript运行时包含了一个待处理的消息队列。每个消息都与一个函数关联。当栈为空的时候,从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数。当栈再次为空的时候,意外这消息处理结束。
事件循环
之所以被称为事件循环,因为它经常被用于如下类似的方式来实现:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
如果当前没有任何消息到来。queue.waitForMessage()会同步阻塞等待消息到来。
执行至完成
每一个消息执行完成后,其它消息才会被执行。当你分析你的程序时,这点提供了一些优秀的特性,包括当一个函数运行时,它不能被取代且会在其它代码运行前先完成。
零延迟
零延迟 (Zero delay) 并不是意味着回调会立即执行。在零延迟调用 setTimeout 时,其并不是过了给定的时间间隔后就马上执行回调函数。其等待的时间基于队列里正在等待的消息数量。
多个运行时互相通信
一个 web worker 或者一个跨域的 iframe 都有它们自己的栈,堆和消息队列。两个不同的运行时只有通过 postMessage 方法进行通信。这个方法会给另一个运行时添加一个消息如果后者监听了 message 事件。
绝不阻塞
一个很有趣的事件循环(event loop)模型特性在于:Javascript跟其他语言不同,它永不阻塞,通常由事件或者回调函数I/0(input /output)处理。