zoukankan      html  css  js  c++  java
  • 【译】并发模型和事件循环

    JavaScript有一个基于“事件循环”的并发模型。这种模型完全不同于从其他语言的,如C和java。

    运行时的概念

    下面的章节解释一个理论模型。现代JavaScript引擎实现和优化所描述的语义。

    直观表示

    函数调用形成一个堆栈的帧。

    当调用bar函数时,第一个帧被创建,它包含了bar的参数和局部变量。当bar调用foo时,第二个帧被创建并被推到第一个帧上,该第一个帧包含foo的参数和局部变量。返回时,顶部帧元素从堆栈中弹出(只留下bar的调用帧)。当bar返回时,堆栈为空。 

     1 function foo(b) {
     2   var a = 10;
     3   return a + b + 11;
     4 }
     5 
     6 function bar(x) {
     7   var y = 3;
     8   return foo(x * y);
     9 }
    10 
    11 console.log(bar(7));
    
    

     对象在堆中分配,该堆只是一个名称,用来表示内存的一个很大的非结构化区域。

    队列

    JavaScript运行时包含消息队列,它是要处理的消息的列表。消息队列是一个与每个消息关联的函数。当堆栈有足够的容量时,将从队列中取出消息并进行处理。处理包括调用关联函数(从而创建初始堆栈帧)。当堆栈再次变空时,消息处理结束。 

    事件循环

    事件循环这个名字的由来,因为它通常是如何实现的,它通常类似于:

    while (queue.waitForMessage()) {
      queue.processNextMessage();
    } 

    当queue.waitForMessage被处理完毕时,才处理queue.processNextMessage。

    完全处理

    在处理任何其他消息之前,每个消息都被完全处理。这特别有助于你推理程序。因为每当一个函数运行,它不能捷足先登,要将之前的任何其他代码完全运行(可以修改数据的函数处理)。这与C不同,例如,如果一个函数在一个线程中运行,它可以在任何点停止运行另一个线程中的其他代码。
    此模型的一个缺点是,如果消息需要太长时间完成,Web应用程序无法处理用户交互,如单击或滚动。浏览器用“脚本运行太长”对话框来缓解这个问题。一个好的做法是使消息处理短,如果可能的话,削减一个消息到几个消息。

    添加消息

    在web浏览器中,任何时候一个事件发生时都会添加消息,并附加有事件侦听器。如果没有侦听器,则事件丢失。因此,单击带有单击事件处理程序的元素将添加一条消息,与其他事件相同。 
    调用setTimeout将在指定的时间后(你设置的第二个参数)向队列中添加消息。如果在队列中没有其他消息,这消息会被立刻处理;不过,如果有消息,setTimeout消息将不得不等待其他要处理的消息先处理完毕。因此,第二个参数表示最小时间,而不是保证时间。

    零延迟

    零延迟实际上并不意味着在零毫秒后执行回调函数。调用setTimeout(零),不一定会在给定的时间间隔后执行回调函数。执行取决于队列中等待任务的数目。在下面的例子中的“this is just a message”将被先于它前面的setTimeout函数(0延迟)处理。因为延迟是运行时处理请求所需的最小时间,但不是保证时间。

     1 (function() {
     2     console.log('this is the start');
     3 
     4     setTimeout(function cb() {
     5         console.log('this is a msg from call back');
     6     });
     7 
     8     console.log('this is just a message');
     9     
    10     setTimeout(function cb1() {
    11         console.log('this is a msg from call back1');
    12     }, 0);
    13     console.log('this is the end');
    14 })();
    15 // "this is the start"
    16 // "this is just a message"
    17 // "this is the end"
    18 // "this is a msg from call back"
    19 // "this is a msg from call back1"

    几个运行时之间的通信

    一个web worker或跨域iframe都拥有自己的堆栈,堆,和消息队列。两个不同的运行时只能通过postMessage方法发送消息进行通信。如果后者监听消息事件,则该方法向其他运行时添加消息。

    从不堵塞

    事件循环模型的一个非常有趣的特性是JavaScript从不阻塞,不像许多其他语言。处理I/O通常是通过事件和回调函数进行的,因此当应用程序等待一个IndexedDB查询返回或XHR请求返回时,它还可以处理其他事情,比如用户输入。

    有遗留的例外存在,像警报或同步XHR,但它被认为是一个很好的实践来避免它们。请注意,异常的异常确实存在(但通常是实现错误,而不是其他)。

     原文链接,翻译难免有出入,欢迎交流和斧正。

  • 相关阅读:
    将现有MySQL数据库改为大小写不敏感
    在Windows中玩转Docker Toolbox
    使用ABP EntityFramework连接MySQL数据库
    数据库设计范式2——BC范式和第四范式
    让OData和NHibernate结合进行动态查询
    文档在线预览的实现
    有哪些老鸟程序员知道而新手不知道的小技巧?自我感受
    EEPROM的概念接口类型及软件实例
    flash的几种模式Normal Mode、DUAL Mode、Quad Mode的概念和区别
    ESP8266 打造一款物联网产品---搭建环境编译及烧录
  • 原文地址:https://www.cnblogs.com/Hale-Proh/p/6698202.html
Copyright © 2011-2022 走看看