NodeJS中的异步I/O、事件驱动

nodejs的主要特点是单线程、异步I/O、事件驱动。让我们先大概了解一下这些名词的意思。

单线程

单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行。在JS引擎中负责解释和执行JavaScript代码的线程只有一个,即主线程。但实际上还存在其他的线程。例如处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程等。这些线程可能存在与JS引擎之内,也可能存在与JS引擎之外,这些线程为工作线程。

同步和异步

同步:执行任务时,后面的任务需要等到前一个任务执行结束才可以执行,任务执行的顺序和任务排列的顺序是相同的 
异步:每个任务有一个或多个callback,前一个任务执行完成以后不是执行后一个任务,而是执行回调函数。后一个任务也不是等到前一个任务执行完成后再执行,程序的执行顺序与任务的排列顺序不一致 
现在我们看一下异步调用的基本过程

var fs = require(‘fs‘);
console.log(‘begin‘);
setTimeout(function(){
    console.log(‘timeout1‘);
},100)

fs.readFile(‘test.txt‘,function(err,data){
    console.log(data);
    console.log(data.toString());
})

setTimeout(function(){
    console.log(‘timeout2‘);
},100)

console.log(‘end‘);

分析一下结果:

由于NodeJS是单线程运行的,首先会顺序执行js文件中的代码,此时事件循环是暂停的。setTimeout和读文件的操作都是异步操作,异步函数会在工作线程执行,当异步函数执行完成以后,将回调函数放入消息队列。当js文件执行完成以后,事件循环开始执行,并从消息队列中取出消息,开始执行回调函数。

而整个异步函数的执行过程如下: 
主线程发起一个异步请求,相应的工作线程接收请求并告知主线程已收到(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作以后,通知主线程;主线程收到通知后,执行一定的动作(调用回调)

事件驱动

事件驱动编程主要思想是通过事件或状态的变化来进行应用程序的流程控制,一般通过事件监听完成,一旦事件被检测到,则调用相应的回调函数。事件驱动主要执行过程是当进来的一个新的请求的时候,请求将会被压入队列中,然后通过一个循环来检测队列中的事件状态变化,如果检测到有状态变化的事件,那么就执行该事件对应的处理代码,一般都是回调函数。

线程驱动是当收到一个请求的时候,将会为该请求开一个新的线程来处理请求。而线程主要是由线程池来管理的。当线程池中有空闲的线程,会从线程池中拿取线程来处理,如果线程池中没有空闲的线程,新来的请求将会进入队列排队,直到线程池中空闲线程

异步I/O

nodejs是单线程运行的,通过一个事件循环来循环取出消息队列中的消息进行处理,处理过程基本上就是去调用该消息对应的回调函数。消息队列就是当一个事件状态发生变化时,就将一个消息压入队列中 
NodeJS的事件循环模型一般要注意下面几点:

  • 因为是单线程的,所以当顺序执行js文件中的代码的时候,事件循环是被暂停的
  • 当JS文件执行完以后,事件循环开始运行,并从消息队列中取出消息,开始执行回调函数
  • 因为是单线程的,所以当回调函数被执行的时候,事件循环是被暂停的
  • 当涉及到I/O的时候,nodejs会开一个独立的线程来进行异步I/O操作,操作结果以后将消息压入消息队列

内部实现

在NodeJS中整个异步I/O模型的基本要素是事件循环、观察者、请求对象和I/O线程池。整个异步I/O的流程图如下:

整个实现过程大概更可以描述为:发起异步请求之后将请求进行封装,封装为请求对象,对请求对象设置参数和回调函数并将请求对象放入线程池,线程池中检查是否有可用线程,当线程可用时执行请求对象的I/O操作,并将执行完成的结果放入请求对象中,通知IOCP调用完成并获取完成的I/O交给I/O观察者。 
在libuv中创建主循环开始事件循环,主循环从I/O观察者中取出可用的请求对象,在请求对象中取出回调函数和I/O结果并调用回调函数

https://segmentfault.com/a/1190000003751278

转载至 :http://blog.csdn.net/charlene0824/article/details/51711154

时间: 2024-10-18 17:02:38

NodeJS中的异步I/O、事件驱动的相关文章

NodeJs中的异步

原文引用https://www.dazhuanlan.com/2019/08/25/5d625d714f62a/ 这篇文章主要讨论NodeJs中的异步问题.使用NodeJs编写进程也一年多了,在公司实习的时候,公司两个项目的后台都是我负责使用NodeJs和Sails框架编写的.工作模式主要是我在服务器端提供RESTful接口,网页端通过AJAX方式获取服务端的数据.在做的过程中,遇到了许多问题,感触最深的是异步编程的思维习惯还不是适应的很好. 异步背景 其实,异步很早都有了,例如在操作系统中就有

nodejs 中的异步之殇

nodejs 中的异步之殇 终于再次回到 nodejs 异步中,以前我以为异步在我写的文章中,已经写完了,现在才发现,还是有很多的地方没有想清楚,下面来一一说明. 模块同步与连接异步 大家应该,经常使用 express 进行网站开发.express 本来的问题不是重点,你肯定要用到第三工具,redis, mysql 了之类的. redis 需要连接,而连接成功需要一个回调(他是一个异步).问题就在这里,这个问题是:倒底是 redis 先连接成功,还是 express 先启动成功? redis.o

如何优雅的处理Nodejs中的异步回调

前言 Nodejs最大的亮点就在于事件驱动, 非阻塞I/O 模型,这使得Nodejs具有很强的并发处理能力,非常适合编写网络应用.在Nodejs中大部分的I/O操作几乎都是异步的,也就是我们处理I/O的操作结果基本上都需要在回调函数中处理,比如下面的这个读取文件内容的函数: fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; console.log(data); }); 那,我们读取两个文件,将这两个文件的内

Nodejs中使用异步流程控制Async

首先,我们都知道,Node基于事件驱动的异步I/O架构,所谓异步就是非阻塞,说白了就是一个事件执行了,我不必等待它执行完成后我才能执行下一个事件.所以在Node环境中的模块基本都是异步的,上一篇说到我在项目中改用了easymysql模块代替mysql模块,两个模块作查询的操作都是异步的,所以要实现嵌套查询往往会很麻烦,而且很大可能会报错.为此,为了实现查询同步,我引进了异步流程控制async模块,让js异步操作变成同步操作,这样一方面方便阅读理解,另一方面能够很好实现需求的目标,亲测有效~ up

NodeJS中常见异步接口定义(get、post、jsonp)

越来越多的人在使用nodeJS,作为一门服务端语言,我们不可避免的要写异步接口(ajax和jsonp).再次强调ajax和jsonp是两个概念,但是由于jquery的封装,使这两种异步接口的调用方式,看起来比较相近,但在底层差别还是比较大的(本文只写服务端的实现). 为了便于讲解我使用express框架来运行我的demo.并分别讲解如何获取参数,并返回结果.本文相当于一个基础篇,只写了一些常见的应用场景.漏掉一些复杂的场景,还望提醒. 一.Ajax——post请求 之所以先从post开始,是因为

nodejs中的异步回调机制

1.再次clear Timer定时器的作用 setTimeOut绝非是传统意义上的"sleep"功能,它做不到让主线程"熄火"指定时间,它是用来指定:某个回调在固定时间后插入执行栈!(实际执行时间略长于这个固定时间) 2.js或nodejs想"sleep"主线程怎么做? 可以自定义sleep休眠函数,原理就是 目标时间 >= 当前时间+sleepTime; 然后不断在while中tick时间.比较.直接看代码吧. function slee

nodejs中的异步流程序控制nsync

异步编程是指由于异步I/O等因素,无法同步获得执行结果时,在回调函数中进行下一步操作的代码编写风格,常见的如setTimeout函数.ajax请求等等http://cnodejs.org/topic/54acfbb5ce87bace2444cbfb并不是node中的,但是我们开发中经常使用使用npm init初始化项目安装cnpm install async --devhttps://www.npmjs.com/package/asynchttp://caolan.github.io/async

nodejs中的子进程,深入解析child_process模块和cluster模块

??node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作.node的单线程模式,只维持一个主线程,大大减少了线程间切换的开销. ??但是node的单线程使得在主线程不能进行CPU密集型操作,否则会阻塞主线程.对于CPU密集型操作,在node中通过child_process可以创建独立的子进程,父子进程通过IPC通信,子进程可以是外部应用也可以是node子程序,子进程执行后可以将结果返回给父进

Node.js(十二)——NodeJs中的Promise

爬虫基于回调和事件的方式去实现,回调也是被诟病已久的问题尤其是callback这种,无论是阅读还是调试都很费劲,甚至我们连代码的堆栈都看不到,这是一种反人类的写法,Promise来拜托这种痛苦的方式 传统方式实现动画效果: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Promise animation</title> <style&g