javascript运行机制:并发模型 与Event Loop

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/52199629

看了阮一峰老师的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做动画时要注意两个问题:

  • 不能使用固定步长作为做动画,一定要使用百分比: 开始值 + (目标值 - 开始值) * (Date.now() - 开始时间)/ 时间区间
  • 如果主进程运行时间过长,会出现跳帧的现象。为了避免setInterval的两个缺点,可以使用链式setTimeout():
setTimeout(function(){
    //其他处理
    setTimeout(arguments.callee, interval);
}, interval);

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的Python

IDEA 神器使用技巧

标记上bookmarks之后可以ctrl 1 ctrl 2 ctrl 3 按标签序号进行跳转

1033
来自专栏崔庆才的专栏

正则表达式中零宽断言的用法

了解了正则表达式,想必一般情况下的匹配都不会出现什么问题,但是如果一些特殊情况,可能需要用到一些更高级的正则表达式匹配操作,本节我们来说明一下正则表达式的一个较...

2874
来自专栏贺贺的前端工程师之路

React中的Redux

整个应用的state被存储在一棵object tree中,并且这个object tree只存在于唯一一个store中。

972
来自专栏前端知识分享

深入理解Vue的生命周期

  谈到Vue的生命周期,相信许多人并不陌生。但大部分人和我一样,只是听过而已,具体用在哪,怎么用,却不知道。我在学习vue一个多礼拜后,感觉现在还停留在初级阶...

1193
来自专栏开源优测

[接口测试 - 基础篇] 08 封装个基本的excel解析类

概述 本文基于openpyxl封装一个excel解析类,请注意,不采用Python的任何高级特性,就简简单单的一个类,实现excel的一些基本操作,并演示如何...

3699
来自专栏更流畅、简洁的软件开发方式

【自然框架】 页面里的父类——把共用的东东都交给父类,让子类专注于其他。

【类图】 ? 【命名空间】——————————————————【文件截图】 ? ? 可能您会问,不就是弄个父类吗,怎么又是这么复杂呢?这个嘛,听...

2278
来自专栏用户2442861的专栏

webStorm 3.0配置使用主题背景色等

http://www.cnblogs.com/jikey/archive/2012/01/16/2323590.html

1501
来自专栏小特工作室

Navi.Soft31.开发工具(含下载地址)

1系统简介 1.1功能简述 在软件开发过程中,我们需要经常对字符串、文件、数据库操作。有时需要浏览Json格式串,有时需要浏览Xml格式串,有时需要读取txt或...

2389
来自专栏前端布道

全方位理解JavaScript的Event Loop

下面我们一个一个的来了解 Event Loop 相关的知识点,最后再一步一步分析出本段代码最后的输出顺序。

913
来自专栏大学生计算机视觉学习DeepLearning

VS下如何建立一个新的MFC程序 网络编程 课设 基于C++ MFC 连接数据库 小应用 小项目浅析展示

3093

扫码关注云+社区

领取腾讯云代金券