Nodejs-1

Node.js的工作机制

Node.js通过V8引擎执行JavaScript代码,使用Node.js API与操作系统交互,并通过Libuv处理异步I/O操作
事件循环和工作线程确保了Node.js的高效和非阻塞特性

工作机制描述:Nodejs通过V8引擎来执行javaScript代码,V8引擎通过Nodejs 的API与操作系统交互,Nodejs又内置了Libuv的异步IO库,内置了事件队列、事件循环、工作线程,用于事件的处理

Nodejs工作机制

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回调机制

在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);
        });
    });
});

为了避免出现这种写法,可以使用基于Promisesasync/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);