当前位置: 首页 > 后端技术 > Node.js

Node.js指南(阻塞与非阻塞概述)

时间:2023-04-03 16:13:51 Node.js

阻塞与非阻塞概述本概述解释了Node.js中阻塞调用和非阻塞调用之间的区别。本概述将涉及事件循环和libuv,但不需要事先了解这些主题,前提是读者对JavaScript语言和Node.js回调模式有基本的了解。“I/O”主要是指与支持libuv的系统的磁盘和网络交互。阻塞阻塞是指在Node.js进程中执行其他JavaScript必须等到非JavaScript操作完成,发生这种情况是因为在阻塞操作发生时事件循环无法继续运行JavaScript。在Node.js中,由于CPU密集而不是等待非JavaScript操作(例如I/O)而表现出较差性能的JavaScript通常不称为阻塞。使用libuv的Node.js标准库中的同步方法是最常用的阻塞操作,原生模块也可能有阻塞方法。Node.js标准库中所有的I/O方法都提供了非阻塞的异步版本并接受回调函数,部分方法还有相应的阻塞方法,其名称以Sync结尾。对比一下代码阻塞方法是同步执行的,非阻塞方法是异步执行的。以文件系统模块为例,这是一个同步读取文件的方法:constfs=require('fs');constdata=fs.readFileSync('/file.md');//在这里阻塞直到文件被读取这是一个等效的异步示例:constfs=require('fs');fs.readFile('/file.md',(err,data)=>{if(err)throwerr;});第一个例子看起来比第二个简单,但缺点是第二行会阻塞任何其他javascript的执行,直到整个文件被读取,注意在同步版本中,如果抛出错误,则需要捕获它,否则进程会崩溃,在异步版本中,是否应该如图所示抛出错误由作者决定。让我们稍微扩展一下示例:constfs=require('fs');constdata=fs.readFileSync('/file.md');//在这里阻塞直到文件是readconsole.log(data);//moreWork();将在console.log之后运行这是一个类似但不等效的异步示例:constfs=require('fs');fs.readFile('/file.md',(err,data)=>{if(err)throwerr;console.log(data);});//moreWork();会在console.log之前运行在上面的第一个例子中,console.log会在moreWork()之前被调用,在第二个例子中,fs.readFile()是非阻塞的,所以JavaScript可以继续执行,moreWork()会被首先调用,无需等待文件读取完成即可运行moreWork()的能力是一个关键的设计选项,可以提高吞吐量。并发性和吞吐量Node.js中的JavaScript执行是单线程的,因此并发性是指事件循环在完成其他工作后执行JavaScript回调函数的能力。任何期望以并发方式运行的代码都必须允许事件循环继续运行,因为正在进行I/O等非JavaScript操作。例如,让我们考虑这样一种情况,每个Web服务器请求需要50毫秒才能完成,这50毫秒中有45毫秒是可以异步完成的数据库I/O,选择非阻塞异步操作可以为每个请求释放45毫秒来处理其他请求,只是选择使用非阻塞方法而不是阻塞方法,是容量上的显着差异。事件循环不同于许多其他语言中的模型,可以创建额外的线程来处理并发工作。混合阻塞和非阻塞代码的危险在处理I/O时应该避免一些模式,让我们看一个例子:constfs=require('fs');fs.readFile('/file.md',(err,data)=>{if(err)throwerr;console.log(data);});fs.unlinkSync('/file.md');在上面的例子中,fs.unlinkSync()很可能发生在fs.readFile()之后,它会在真正读取file.md之前删除它,更好的写法是完全非阻塞并保证按正确的顺序执行:constfs=require('fs');fs.readFile('/file.md',(readFileErr,data)=>{if(readFileErr)throwreadFileErr;console.log(data);fs.unlink('/file.md',(unlinkErr)=>{如果(unlinkErr)抛出unlinkErr;});});上面在fs.readFile()的回调中对fs.unlink()进行了非阻塞调用,这保证了正确的操作顺序。关于Node.js上libuv的其他资源上一篇文章:迁移到安全的Buffer构造函数下一篇文章:Node.js事件循环、计时器和process.nextTick()