Node.js是一个异步非阻塞I/O的JavaScript运行环境。在Node.js中非阻塞I/O是其最主要的特征。异步、事件驱动、非阻塞I/O是Node.js存在的原因之一。理解Node.js的阻塞与非阻塞是非常重要的。
什么是阻塞与非阻塞
阻塞是指在某个操作执行过程中会阻碍后续代码的运行。非阻塞指在某个操作执行过程中不会阻碍后续代码的运行。
在I/O操作中,阻塞在读取或写入数据时会阻塞后续代码的运行,而非阻塞则不会。
阻塞I/O
Node.js中的阻塞I/O是指在执行I/O操作时,阻塞后续代码的运行。由于Node.js是单线程运行,当主线程遇到阻塞I/O操作时,它将会停滞在那里等待I/O操作执行完成返回,阻塞了代码的执行和服务器的响应。
下面是一个阻塞I/O的例子:
const fs = require('fs');
// 在执行完读文件的操作之后会继续执行后面的代码
const data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log('程序执行结束');
fs.readFileSync()
是Node.js的同步I/O函数,它会阻塞代码的执行并等待文件读取完毕返回数据后再执行后面的代码。因此在读取文件的过程中,程序被阻塞住,直到文件读取完毕并返回数据后才会输出数据和"程序执行结束"。
非阻塞I/O
Node.js中的非阻塞I/O是指在执行I/O操作时,不会阻塞后续代码的运行。Node.js通过事件循环机制实现非阻塞I/O。
下面是一个非阻塞I/O的例子:
const fs = require('fs');
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log(data.toString());
});
console.log('程序执行结束');
fs.readFile()
是Node.js的异步I/O函数,它会将I/O操作加入到事件队列中,继续执行后续代码,等待I/O事件完成后会被扔到事件循环机制中执行回调函数。因此在读取文件的过程中,程序会继续执行后续代码,输出"程序执行结束",直到文件读取完毕后才会输出文件数据。
阻塞I/O与非阻塞I/O的对比
阻塞I/O会在I/O操作完成前阻碍后续代码的执行,而非阻塞I/O不会阻碍后续代码的执行,因此非阻塞I/O对于I/O密集型的场景非常有用。
Node.js采用一种事件循环的机制来处理I/O请求。在事件循环的每一个循环次数中,Node.js都会从事件队列中取出并处理一个事件。如果事件处理函数中触发了I/O请求,那么程序会将请求交给操作系统并继续往后执行,直到I/O操作完成并触发相应的回调函数。
Node.js中通过回调函数的方式解决了阻塞I/O带来的性能问题,使得Node.js在I/O密集型的场景中有非常优异的表现。
示例说明
示例1:文件夹遍历
下面是一个使用Node.js来遍历指定文件夹的例子,使用阻塞和非阻塞的方式分别实现:
- 阻塞方式
const fs = require('fs');
function getFileList(path) {
const fileArr = [];
const fileList = fs.readdirSync(path);
fileList.forEach(function(file) {
fileArr.push(file);
});
return fileArr;
}
const list = getFileList('./');
console.log(list);
- 非阻塞方式
const fs = require('fs');
function getFileList(path) {
const fileArr = [];
fs.readdir(path, function(err, fileList) {
fileList.forEach(function(file) {
fileArr.push(file);
});
console.log(fileArr);
});
}
getFileList('./');
示例2:HTTP服务器
下面是一个使用Node.js实现的简单的HTTP服务器,使用阻塞和非阻塞的方式分别实现:
- 阻塞方式
const http = require('http');
const fs = require('fs');
http.createServer(function (req, res) {
const data = fs.readFileSync('index.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
}).listen(8080);
console.log('服务器启动成功!请在浏览器中访问 http://localhost:8080');
- 非阻塞方式
const http = require('http');
const fs = require('fs');
http.createServer(function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
});
}).listen(8080);
console.log('服务器启动成功!请在浏览器中访问 http://localhost:8080');
在执行这个简单的HTTP服务器时,使用非阻塞方式的服务器在文件读取的同时可以继续响应客户端请求,而使用阻塞方式的服务器必须等待文件读取完成后才能响应客户端请求,性能明显落后。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Node.js 阻塞与非阻塞的实现 - Python技术站