-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[译]如何理解并发模型(concurrency model)和事件循环(event loop)? #216
Comments
初识并发模型和事件循环JavaScript拥有基于event loop的并发模型。 基于event loop的并发模型是什么?
运行时概念下面的这些部分解释了理论模型。 可视化呈现栈(stack)从frames stack中调用函数。 function foo(){
let a = 10;
return a + b + 11
}
function bar(x){
let y = 3;
return foo(x*y);
}
console.log(bar(7)); // 返回42 过程拆解:
可视化拆解: 堆(Heap)对象被分配在heap中,之所以称之为堆是因为它会占用大量的内存(很多都是非结构化的)。 队列(Queue)JavaScript运行时使用的是message queue,它的意思是有一个消息列表去处理。 在事件循环的一些点,runtime开始处理队列中的消息,从最老的一个开始。为了做到这样,消息会从队列中移除,并且使用消息作为输入参数调用相应的函数。通常来讲,调用一个函数会在栈中生成一个新的frame。 函数的处理一直会进行,知道stack被清空。然后event loop去处理下一个在队列中的消息。 如何理解”使用消息作为输入参数调用相应的函数“?上面的例子中,foo执行完之后会从call stack中出栈,也就是说这个foo的消息从消息队列中移除。 事件循环初识事件循环event loop之所以叫这个名字,是因为它的实现方式,可以看成下面的伪代码: while(queue.waitForMessage()){
queue.processNextMessage()
} queue.waitForMessage()同步等待消息到达(如果有一个消息是可用并且是等待处理的。) ”执行到完成“每个消息都会在下一个消息处理完成前完成。 这为你的程序带来了很大的好处,其中包括:无论何时调用一个函数,它都不能被预清空而且会在任何的代码运行前完全运行(而且可以修改函数操作的数据)。这和C不一样,例如:如果一个函数运行在一个线程中,它也许会在任何时间被运行系统停止,然后去其它的线程去运行其他的代码。 这种模型有一个缺点:如果一个消息花了很长时间才能完成,web应用不能到达去处理用户的click或者scroll事件。浏览器可以通过一个”script占用过长的时间去执行“的对话框告知用户。一个很好的实践是使得message变短,并且尽可能将一个消息拆解成多个消息。 增加消息在web浏览器中,消息可以在时间发生的任意时间被添加,并且会有一个事件listener附加在其上。如果没有listener,event会丢失。所以当一个click事件发生在元素上时,click事件的处理器会添加一个message。其他任何的事件都是这样的。 setTimeout添加message到queue的过程
setTimeout有两个参数:第一callback是被增加到queue的message,第二个是最小时间(默认为0)。time的值代表着message被推入到queue的最小时间。如果没有其他的消息在queue中,并且这个栈是空的,消息会在delay的时间后被处理。然而,如果有消息,setTimeout的消息需要等待其他的消息处理完成后再执行。 因为这个原因,第二个参数代表着最小时间,并不是保证时间。 “setTimeout不能准时执行”可以看下面这个例子去理解: const s = new Date().getSeconds();
setTimeout(function() {
// 打印出了2,意味着并没有准时在500ms后执行
console.log("在(new Date().getSeconds() - s)秒后打印。");
}, 500)
while (true) {
if (new Date().getSeconds() - s >= 2) {
console.log("循环了2秒")
break;
}
} 零延迟(Zero delay)零延迟的意思是函数不能在0ms后立即执行。 执行需要依赖队列中等待的任务数量。在下面的例子中,消息 基本上,setTimeout需要等待队列消息中的所有代码执行完成,即使你为setTimout指定了一个精准的时间。 (function() {
console.log('this is the start');
setTimeout(function cb() {
console.log('Callback 1: this is a msg from call back');
}); // has a default time value of 0
console.log('this is just a message');
setTimeout(function cb1() {
console.log('Callback 2: this is a msg from call back');
}, 0);
console.log('this is the end');
})();
// "this is the start"
// "this is just a message"
// "this is the end"
// "Callback 1: this is a msg from call back"
// "Callback 2: this is a msg from call back" 多个运行时互相通信一个web worker或者是跨域的iframe都有自己的stack,heap和消息队列。 从不阻塞JavaScript的事件循环模型有一个非常有趣的属性,它不像其他的语言,js不会阻塞。 参考资料:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop |
The text was updated successfully, but these errors were encountered: