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程序设计有所帮助。

(0)

相关推荐

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

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

  • 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 异步IO和事件循环

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

  • 深入浅析Node.js 事件循环

    Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. (来源于Javascript是单线程又是异步的,但是这种语言有个共同的特点:它们是 event-driven 的.驱动它们的 event 来自一个异构的平台.) 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事件循环(Event Loop)和线程池详解

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

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

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

  • 实例分析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)的解析

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

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

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

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

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

随机推荐