node.js中对Event Loop事件循环的理解与应用实例分析


Posted in Javascript onFebruary 14, 2020

本文实例讲述了node.js中对Event Loop事件循环的理解与应用。分享给大家供大家参考,具体如下:

javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务。

同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行。

异步任务是不进入主线程,而是进入一个 "任务队列" 里,"任务队列" 通知主线程,该异步任务才会进入主线程执行。

任务的运行机制如下:

1、所有同步任务在主线程上执行,形成一个 "执行栈",注意栈是先进后出的。

2、主线程外,有一个 "任务队列" ,只要异步任务处理完有结果了,就在 "任务队列" 中放置一个事件,注意队列是先进先出的。

3、一旦 "执行栈" 中所有同步任务执行完毕。系统读取 "任务队列" 中的事件,对应的异步任务。放入 "执行栈" 中,开始执行。

4、主线程不断重复第三步,这种循环从 "任务队列" 中读取事件处理的这种运行机制称为Event Loop(事件循环)。

"执行栈" 中的同步代码总是比 "任务队列"中的异步任务之前运行。

function fun() {
  setTimeout(function () {
    console.log('异步任务');
  }, 0);
  console.log(1);
  console.log(2);
  console.log(3);
  console.log(4);
  console.log(5);
}
fun();

上面的代码,console.log代码写在setTimeout后面,但仍然先执行。

"任务队列" 是一个队列,队列的特性是先进先出。看下面代码:

function fun() {
  console.log(1);
  setTimeout(function () {
    console.log(2);
    setTimeout(function () {
      console.log(3);
    }, 0);
  }, 0);
  console.log(4);
}
fun();

输出结果为 1  4  2  3,打印 2 的setTimeout任务比打印 3 的setTimeout任务先进入队列,所以会先运行。

对于异步操作,像ajax,只有操作成功后返回结果,才会进入 "任务队列" 中,而不是调用的时候就放入队列中。看下面代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script>
  function ajax() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://mail.163.com/', true);
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
      }
    };
  }
  function fun() {
    console.log(1);
    ajax();
    setTimeout(function () {
      console.log(2);
    }, 1000);
    console.log(3);
  }
  fun();
</script>
</body>
</html>

ajax() 与 setTimeout 谁先进入队列,谁先输出,是需要看两者消耗时间,谁更短。时间短的会先进入队列先运行。

setTimeout 与 setInterval 运行机制一样,都是在指定时间把事件插入到 "任务队列" 尾部。区别是前者只执行一次,后者可反复执行。

node.js 还为我们提供了,process.nextTick 和 setImmediate 与 "任务队列" 有关的方法。

process.nextTick 会把回调函数放在当前 "执行栈" 的尾部。也就是说是在读取 "任务队列" 之前运行。

function fun() {
  console.log(1);
  setTimeout(function () {
    console.log(2);
  }, 0);
  process.nextTick(function () {
    console.log(3);
    process.nextTick(function () {
      console.log(4);
    });
  });
  process.nextTick(function () {
    console.log(5);
  });
  console.log(6);
}
fun();

上面的代码会输出 1  6  3  5  4  2 ,注意process.nextTick会把回调函数放在 "执行栈" 的尾部。

同步代码最先输出 1  6,然后 3 的先放入尾部,然后 5 的跟在 3 后面。3先执行,然后把 4 放入到 5 的后面。5执行完后,再执行4,最后读取 "任务队列" 中的输出2。

setImmediate 会把回调函数放在当前 "任务队列" 的尾部。也就是下一次事件循环Event Loop时执行。

function fun() {
  console.log(1);
  setTimeout(function () {
    console.log(2);
  }, 0);
  setImmediate(function () {
    console.log(3);
  });
  console.log(4);
}
fun();

上面的代码是会输出 1  4  2  3 还是 1  4  3  2 是不确定的,因为setTimeout 与 setImmediate 都会在下一次事件循环Event Loop中触发,所以输出是不确定的。

希望本文所述对大家node.js程序设计有所帮助。

Javascript 相关文章推荐
扩展easyui.datagrid,添加数据loading遮罩效果代码
Nov 02 Javascript
JS高级拖动技术 setCapture,releaseCapture
Jul 31 Javascript
利用js实现选项卡的特别效果的实例
Mar 03 Javascript
无缝滚动js代码通俗易懂(自写)
Jun 19 Javascript
一款基于jQuery的图片场景标注提示弹窗特效
Jan 05 Javascript
javascript等号运算符使用详解
Apr 16 Javascript
Javascript设计模式理论与编程实战之简单工厂模式
Nov 03 Javascript
javascript 显示全局变量与隐式全局变量的区别
Feb 09 Javascript
为JQuery EasyUI 表单组件增加焦点切换功能的方法
Apr 13 jQuery
vue项目中使用lib-flexible解决移动端适配的问题解决
Aug 23 Javascript
JS二级菜单不同实现方法分析【4种方法】
Dec 21 Javascript
原生js实现获取form表单数据代码实例
Mar 27 Javascript
Angular之jwt令牌身份验证的实现
Feb 14 #Javascript
node.js中module模块的功能理解与用法实例分析
Feb 14 #Javascript
JS实现简易计算器
Feb 14 #Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
Feb 14 #Javascript
node.js中npm包管理工具用法分析
Feb 14 #Javascript
vue-cli创建的项目中的gitHooks原理解析
Feb 14 #Javascript
基于vue的tab-list类目切换商品列表组件的示例代码
Feb 14 #Javascript
You might like
php数组应用之比较两个时间的相减排序
2008/08/18 PHP
php类常量的使用详解
2013/06/08 PHP
使用array_map简单搞定PHP删除文件、删除目录
2014/10/29 PHP
php通过修改header强制图片下载的方法
2015/03/24 PHP
PHP的Yii框架中创建视图和渲染视图的方法详解
2016/03/29 PHP
thinkphp中多表查询中防止数据重复的sql语句(必看)
2016/09/22 PHP
解决PHP程序运行时:Fatal error: Maximum execution time of 30 seconds exceeded in的错误提示
2016/11/25 PHP
php格式化时间戳
2016/12/17 PHP
PHP检查端口是否可以被绑定的方法示例
2018/08/09 PHP
PHP array_reduce()函数的应用解析
2018/10/28 PHP
IE bug table元素的innerHTML
2010/01/11 Javascript
javascript跨域刷新实现代码
2011/01/01 Javascript
js实现按钮加背景图片常用方法
2014/11/01 Javascript
简介JavaScript中fixed()方法的使用
2015/06/08 Javascript
jquery弹出遮掩层效果【附实例代码】
2016/04/28 Javascript
详解JavaScript数组过滤相同元素的5种方法
2017/05/23 Javascript
Cookbook组件形式:优化 Vue 组件的运行时性能
2018/11/25 Javascript
Web安全之XSS攻击与防御小结
2018/12/13 Javascript
微信小程序实现文字从右向左无限滚动
2020/11/18 Javascript
微信小程序封装的HTTP请求示例【附升级版】
2019/05/11 Javascript
vue.js click点击事件获取当前元素对象的操作
2020/08/07 Javascript
[03:04]DOTA2英雄基础教程 影魔
2013/12/11 DOTA
python+mysql实现简单的web程序
2014/09/11 Python
Linux中安装Python的交互式解释器IPython的教程
2016/06/13 Python
Python3中使用PyMongo的方法详解
2017/07/28 Python
浅析Python中return和finally共同挖的坑
2017/08/18 Python
基于python实现学生管理系统
2018/10/17 Python
在Python中实现shuffle给列表洗牌
2018/11/08 Python
Python实现读取并写入Excel文件过程解析
2020/05/27 Python
使用anaconda安装pytorch的实现步骤
2020/09/03 Python
可能这些是你想要的H5软键盘兼容方案(小结)
2019/04/23 HTML / CSS
领导四风问题整改措施思想汇报
2014/10/13 职场文书
2015年求职自荐信范文
2015/03/04 职场文书
2015年基建工作总结范文
2015/05/23 职场文书
使用feign服务调用添加Header参数
2021/06/23 Java/Android
Nginx跨域问题解析与解决
2022/08/05 Servers