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 相关文章推荐
url地址自动加#号问题说明
Aug 21 Javascript
兼容IE和FF的js脚本代码小结(比较常用)
Dec 06 Javascript
js实现跨域访问的三种方法
Dec 09 Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
Dec 29 Javascript
JQuery 的跨域方法推荐_可跨任何网站
May 18 Javascript
JS拉起或下载app的实现代码
Feb 22 Javascript
VUE实现表单元素双向绑定(总结)
Aug 08 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
Apr 10 Javascript
微信小程序中为什么使用var that=this
Aug 27 Javascript
layer ui插件显示tips时,修改字体颜色的实现方法
Sep 11 Javascript
在博客园博文中添加自定义右键菜单的方法详解
Feb 05 Javascript
vue绑定class的三种方法
Dec 24 Vue.js
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的历史和优缺点
2006/10/09 PHP
php,不用COM,生成excel文件
2006/10/09 PHP
BBS(php &amp; mysql)完整版(六)
2006/10/09 PHP
php生成图片验证码-附五种验证码
2015/08/19 PHP
浅析Yii2 gridview实现批量删除教程
2016/04/22 PHP
thinkPHP5.0框架环境变量配置方法
2017/03/17 PHP
jquery 常用操作方法
2010/01/28 Javascript
指定区域的图片自动按比例缩小的js代码(防止页面被图片撑破)
2014/02/21 Javascript
Node.js和PHP根据ip获取地理位置的方法
2014/03/14 Javascript
jQuery实现的多屏图像图层切换效果实例
2015/05/07 Javascript
jQuery实现的网页竖向菜单效果代码
2015/08/26 Javascript
学习使用AngularJS文件上传控件
2016/02/16 Javascript
全面了解addEventListener和on的区别
2016/07/14 Javascript
angularJS 如何读写缓冲的方法(推荐)
2016/08/06 Javascript
使用Javascript判断浏览器终端设备(PC、IOS(iphone)、Android)
2017/01/04 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
从零开始做一个pagination分页组件
2017/03/15 Javascript
解决Vue 浏览器后退无法触发beforeRouteLeave的问题
2017/12/24 Javascript
bootstrapTable+ajax加载数据 refresh更新数据
2018/08/31 Javascript
[01:03:00]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第一局
2016/02/25 DOTA
Python全局变量用法实例分析
2016/07/19 Python
python实现控制台打印的方法
2019/01/12 Python
python中的decimal类型转换实例详解
2019/06/26 Python
使用 Supervisor 监控 Python3 进程方式
2019/12/05 Python
关于tensorflow的几种参数初始化方法小结
2020/01/04 Python
Python脚本导出为exe程序的方法
2020/03/25 Python
Python实现手势识别
2020/10/21 Python
matplotlib绘制多子图共享鼠标光标的方法示例
2021/01/08 Python
中层竞聘演讲稿
2014/01/09 职场文书
宠物店的创业计划书范文
2014/01/11 职场文书
秋季运动会广播稿大全
2014/02/17 职场文书
婚礼证婚人演讲稿
2014/09/13 职场文书
办公经费申请报告
2015/05/15 职场文书
2016同学毕业寄语大全
2015/12/04 职场文书
nginx实现发布静态资源的方法
2021/03/31 Servers
k8s部署redis cluster集群的实现
2021/06/24 Redis