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

本文实例讲述了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程序设计有所帮助。

时间: 2020-02-14

详解nodejs异步I/O和事件循环

事件驱动模型 现在我们来看看nodejs中的事件驱动和异步I/O是如何实现的. nodejs是单线程(single thread)运行的,通过一个事件循环(event-loop)来循环取出消息队列(event-queue)中的消息进行处理,处理过程基本上就是去调用该消息对应的回调函数.消息队列就是当一个事件状态发生变化时,就将一个消息压入队列中. nodejs的时间驱动模型一般要注意下面几个点: 因为是单线程的,所以当顺序执行js文件中的代码的时候,事件循环是被暂停的. 当js文件执行完以后,事

深入理解Node.js 事件循环和回调函数

本文详细的介绍了Node.js 事件循环和Node.js回调函数,废话不多说了,具体看下面把.  一.Node.js 事件循环 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高.Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发.Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现.Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观

小结Node.js中非阻塞IO和事件循环

学习和使用Node.js已经有两个月,使用express结合mongoose写了一个web应用和一套RESTful web api,回过头来看Node.js官网首页对Node.js的介绍:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.那么其中的non-blocking I/O model 意味着什么呢? 非阻塞的IO模型 首先,IO操作无疑是耗时的,当服务器

深入浅析Node.js 事件循环

Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. (来源于Javascript是单线程又是异步的,但是这种语言有个共同的特点:它们是 event-driven 的.驱动它们的 event 来自一个异构的平台.) Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件

实例分析JS与Node.js中的事件循环

这两天跟同事同事讨论遇到的一个问题,js中的event loop,引出了chrome与node中运行具有setTimeout和Promise的程序时候执行结果不一样的问题,从而引出了Nodejs的event loop机制,记录一下,感觉还是蛮有收获的 console.log(1) setTimeout(function() { new Promise(function(resolve, reject) { console.log(2) resolve() }) .then(() => { con

Node.js事件循环(Event Loop)和线程池详解

Node的"事件循环"(Event Loop)是它能够处理大并发.高吞吐量的核心.这是最神奇的地方,据此Node.js基本上可以理解成"单线程",同时还允许在后台处理任意的操作.这篇文章将阐明事件循环是如何工作的,你也可以感受到它的神奇. 事件驱动编程 理解事件循环,首先要理解事件驱动编程(Event Driven Programming).它出现在1960年.如今,事件驱动编程在UI编程中大量使用.JavaScript的一个主要用途是与DOM交互,所以使用基于事件

浅谈Node 异步IO和事件循环

前言 学习Node就绕不开异步IO, 异步IO又与事件循环息息相关, 而关于这一块一直没有仔细去了解整理过, 刚好最近在做项目的时候, 有了一些思考就记录了下来, 希望能尽量将这一块的知识整理清楚, 如有错误, 请指点轻喷~~ 一些概念  同步异步 & 阻塞非阻塞 查阅资料的时候, 发现很多人都对 异步和非阻塞 的概念有点混淆, 其实两者是完全不同的, 同步异步指的是 行为即两者之间的关系 , 而阻塞非阻塞指的是 状态即某一方 . 以前端请求为一个例子,下面的代码很多人都应该写过 $.ajax(

Node.js Event Loop各阶段讲解

Event Loop阶段描述图 timers timer阶段处理setTimeout于setInterval回调,开始处理的时机与poll阶段有关联. pending callbacks 该阶段执行某些系统操作的回调,比如TCP套接字在连接时收到ECONNREFUSED. 网上有一些将该阶段称为I/O callbacks的文章都是过时错误的,具体可以移步Node.js官方库下面的这个issue: #1118. idle, prepare 内部使用,忽略. poll poll是一个核心阶段,等新I

Node.js 事件循环详解及实例

 Node.js  事件循环详解及实例 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数. Node.js 有多个内置的事件,我们可以

Nodejs监控事件循环异常示例详解

开场白 最近在学习 libuv,也了解了一些 Node.js 中使用 libuv 的例子.当然,这篇文章不会去介绍 event loop,毕竟这些东西在各个论坛.技术圈里都被介绍烂了.本文介绍如何正确使用 Event loop,以及即使发现程序是否异常 block. 基础 event loop 的基础想必各位读者都比较熟悉了.这里我引用官方的图,简单介绍两句,作为前置准备: event loop是作为单线程实现异步的方式之一.简而言之,就是在一个大的 while 循环中不断遍历这些 phase,

Node.JS中事件轮询(Event Loop)的解析

当我们知道I/O操作和创建新线程的开销是巨大的! 网站延迟的开销 对于一个网站,后台大多不需要进行复杂的计算,我们的程序大多时间花费在I/O读取上. 看到一个数据:IO操作可以比数据处理慢几个数量级.高端SSD固态硬盘的读取速度可以达到200mb-700mb/s;读取1000字节需要1.4微秒.而在此期间,2GHZ频率的CPU可以执行28000个指令处理周期.而网络数据的IO甚至更慢! NodeJS采用单线程非阻塞的架构解决老大难的IO问题 当采用多线程时,为每一个请求开启一个新的线程(Apac

node.js中事件触发器events的使用方法实例分析

本文实例讲述了node.js中事件触发器events的使用方法.分享给大家供大家参考,具体如下: node.js是基于事件驱动的,通过events,我们可以方便的创建事件,并通过触发事件来调用我们自定义的监听函数. 所有能触发事件的对象都应该是 EventEmitter 类的实例,一般我们自定义一个类继承于 EventEmitter 类. 通过on()方法我们可以绑定事件与监听函数: const Events = require('events'); //自定义一个类,继承于EventEmitt

详解Node.js中的事件机制

前言 在前端编程中,事件的应用十分广泛,DOM上的各种事件.在Ajax大规模应用之后,异步请求更得到广泛的认同,而Ajax亦是基于事件机制的. 通常js给我们的第一印象就是运行在客户端浏览器上面的脚本,通过node.js我们可以在服务端运行javascript. node.js是基于单线程无阻塞异步式的I/O,异步式的I/O指的是当遇到I/O操作的时候,线程不阻塞而是进行下面的操作,那么I/O操作完成之后,线程时如何知道该操作完成的呢? 当操作完成耗时的I/O操作之后,会以事件的形式通知I/O操

node.js事件轮询机制原理知识点

借助libuv库实现的 概括事件轮询机制:分为六个阶段 1.timers 定时器阶段 计时和执行到点的定时器回调函数 2.pending callbacks 某些系统操作(例如TCP错误类型) 3.idle,prepare 4.poll轮询阶段(轮询队列) 如果轮询队列不为空,依次同步取出轮询队列中第一个回调函数,直到轮询队列为空或者达到系统最大限制 如果轮询队列为空 如果之前设置过setImmediate函数,直接进入下一个check阶段,如果之前没有设置过setImmediate函数,在当前

Node.js中HTTP模块与事件模块详解

Node.js的http服务器 通过使用HTTP模块的低级API,Node.js允许我们创建服务器和客户端.刚开始学node的时候,我们都会遇到如下代码: 复制代码 代码如下: var http = require('http'); http.createServer(function (req,res) {     res.end('Hello World\n'); }).listen(3000,"127.0.0.1"); console.log("Server funni

在Node.js中使用HTTP上传文件的方法

开发环境 我们将使用 Visual Studio Express 2013 for Web 作为开发环境, 不过它还不能被用来做 Node.js 开发.为此我们需要安装 Node.js Tools for Visual Studio.  装好后 Visual Studio Express 2013 for Web 就会转变成一个 Node.js IDE 环境,提供创建这个应用所需要的所有东西..而基于这里提供的指导,我们需要: 下载安装 Node.js  Windows 版,选择适用你系统平台的

浅谈Node.js中的定时器

Node.js中定时器的实现 上一篇博文提到,在Node中timer并不是通过新开线程来实现的,而是直接在event loop中完成.下面通过几个JavaScript的定时器示例以及Node相关源码来分析在Node中,timer功能到底是怎么实现的. JavaScript中定时器功能的特点 无论是Node还是浏览器中,都有setTimeout和setInterval这两个定时器函数,并且其工作特点基本相同,因此下面仅以Node为例进行分析. 我们知道,JavaScript中的定时器并不同于计算机