Node.js的工作机制
Node.js通过V8引擎执行JavaScript代码,使用Node.js API与操作系统交互,并通过Libuv
处理异步I/O操作
事件循环和工作线程确保了Node.js的高效和非阻塞特性
工作机制描述:Nodejs通过V8引擎来执行javaScript代码,V8引擎通过Nodejs 的API与操作系统交互,Nodejs又内置了Libuv
的异步IO库,内置了事件队列、事件循环、工作线程,用于事件的处理
1.V8 是 Chrome 浏览器的 JavaScript 引擎,它将 JavaScript 代码编译成机器码以提高执行效率
2.Libuv 是一个跨平台的异步 I/O 库,它在 Node.js 下运行,用于处理文件系统、网络和进程等异步操作。Libuv 使用事件循环和工作线程来处理这些操作,而不会阻塞主线程。
3.Event Loop:这是 Node.js 的核心概念之一。事件循环不断检查事件队列
,处理事件和执行回调函数。它确保了 Node.js 的非阻塞和事件驱动的特性。
4.Event Queue:事件队列用于存储即将处理的事件。当一个异步操作完成时,相关的回调函数会被放入事件队列中,等待事件循环处理
。
5.Worker Threads:这些是用于处理阻塞操作的线程,如文件读写、网络请求等。它们允许 Node.js 在不阻塞主线程的情况下执行这些操作。
6.Blocking Operation:这些是可能阻塞线程的操作,如同步的文件读写。在 Node.js 中,这些操作通常被放在工作线程中执行,以避免阻塞事件循环。
7.Execute Callback:一旦一个异步操作完成,它的回调函数就会被执行。这是通过事件循环来管理的。
模块加载
const module = require('module-name') ;
module-name 可以是一个文件路径,也可以是一个模块名称
如果是一个模块名称,Node.js 会自动从 node_modules 目录中查找该模块。
npm
使用npm 来安装模块,如
npm install express
安装完成之后,express包就放在了工程目录下的node_modules目录中,因此代码只需要通过require(‘express’)
创建模块,package.json 文件是必不可少的。我们可以使用 NPM 生成 package.json 文件,生成的文件包含了基本的结果
变量的使用
变量的声明需要使用var 关键字,如果没有使用var 关键字变量会直接打印出来
使用 var 关键字的变量可以使用 console.log()
来输出变量。
Node.js 回调函数
Node.js由于使用了V8引擎,导致javaScript可以脱离浏览器运行在服务器端
Node.js的核心特性之一就是其非阻塞I/O(输入/输出)模型,异步编程的直接体现就是回调
在Node.js中,回调函数是一种异步编程模式,用于处理I/O操作,如文件读写,数据库交互,网络请求等
这些操作通常需要花费较长时间,如果采用同步方式,会阻塞整个程序的执行,直到操作完成
使用回调函数,Node.js 可以在 I/O 操作进行时继续执行其他代码,一旦 I/O 操作完成,再执行回调函数。
Node.js 是单线程的,但通过事件驱动和回调机制实现异步操作。
回调函数一般作为函数的最后一个参数出现:
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
回调地狱(Callback Hell)
fs.readFile('file1.txt', 'utf8', (err, data1) => {
if (err) {
console.error('Error reading file1:', err);
return;
}
fs.readFile('file2.txt', 'utf8', (err, data2) => {
if (err) {
console.error('Error reading file2:', err);
return;
}
fs.readFile('file3.txt', 'utf8', (err, data3) => {
if (err) {
console.error('Error reading file3:', err);
return;
}
console.log('Data from all files:', data1, data2, data3);
});
});
});
为了避免出现这种写法,可以使用基于Promises
的async/await
,这是更接近同步代码风格的异步编程方式
const fs = require('fs').promises;
async function readFiles() {
try {
const data1 = await fs.readFile('file1.txt', 'utf8');
const data2 = await fs.readFile('file2.txt', 'utf8');
const data3 = await fs.readFile('file3.txt', 'utf8');
console.log('Data from all files:', data1, data2, data3);
} catch (err) {
console.error('Error reading files:', err);
}
}
readFiles();
普通写法的回调函数
const userdatabase = []
function checkuserExist(username , callback){
const isAvailable = !userdatabase.includes(username);
callback(isAvailable);
}
function SaveUser(username,callback){
userdatabase.push(username);
callback(`用户 ${username} 成功注册`);
}
function registerUser(username){
checkuserExist(username,(isAvailable)=>{
if(!isAvailable){
console.log(`用户 ${username} 已被注册`);
return;
}
SaveUser(username,(message)=>{
console.log(message);
});
});
}
// 测试注册用户
registerUser('Alice'); // 第一次注册
registerUser('Bob'); // 第二次注册
setTimeout(() => {
registerUser('Alice'); // 尝试重复注册
}, 3000);
Promise写法:
// 模拟的数据库
const usersDatabase = [];
// 模拟异步检查用户名是否可用
function checkUsernameAvailability(username) {
return new Promise((resolve) => {
setTimeout(() => {
const isAvailable = !usersDatabase.includes(username);
resolve(isAvailable);
}, 1000); // 模拟 1 秒的延迟
});
}
// 模拟异步保存用户信息
function saveUser(username) {
return new Promise((resolve) => {
setTimeout(() => {
usersDatabase.push(username);
resolve(`用户 ${username} 注册成功!`);
}, 1000); // 模拟 1 秒的延迟
});
}
// 用户注册函数
async function registerUser(username) {
const isAvailable = await checkUsernameAvailability(username);
if (!isAvailable) {
console.log(`用户名 ${username} 已被注册!`);
return;
}
const message = await saveUser(username);
console.log(message);
}
// 测试注册用户
registerUser('Alice'); // 第一次注册
registerUser('Bob'); // 第二次注册
setTimeout(() => {
registerUser('Alice'); // 尝试重复注册
}, 3000);