是什么?nodejs是基于Chrome V8引擎的JavaScript运行环境,它可以使JavaScript代码在服务器上运行。
有什么不同?第一,nodejs采用事件驱动、非阻塞式I/O模型,让其轻量且高效。nodejs在处理大量并发连接时,能够保持高效的性能,因为它不会每个连接都创建新的线程,而是使用单线程处理请求。这种模式降低了系统的开销,提高了整体的吞吐量。第二,nodejs是单线程的,这避免了多线程编程中的一些问题,比如线程间的数据同步和线程管理开销。第三,nodejs具有强大的包管理器npm,这有利于开发者安装和管理第三方模块。
事件驱动:nodejs采用事件驱动的编程模式,它通过事件来触发回调函数。当web服务器接收到一个请求时,不会立即处理,而是将请求放到事件队列中。主线程会不断监听事件队列,有新事件触发,就会执行相应的回调函数来处理请求。这可以使nodejs同时处理多个请求。
非阻塞I/O:nodejs使用非阻塞I/O模型,该模型不会每个请求都创建一个新的线程或开启新的事件。相反,当服务器接收到一个请求时,它会立即返回并继续处理其他请求。对于需要执行I/O的操作,如读写文件、网络请求等,nodejs会将其放到一个线程池中进行异步处理。这样,主线程可以继续监听事件队列,而不需要等待I/O操作完成、当I/O操作完成,它会通过事件触发相应的回调函数来处理。
1.使用try-catch语句来捕获和处理错误
try { //可能抛出异常的代码 }catch(err){ //处理错误的代码 }
2.使用回调函数
nodejs的部分API都可以接受回调函数作为最后一个参数,用来处理错误。
fs.readFile('/c:/files/a.txt',function(err,data){ if(err){ //处理错误 }else{ //处理数据 } }
3.使用Promise
getData().then(res => { //处理数据 }).catch(err => { //处理错误 })
4.async/await
async/await是Promise的语法糖,使异步代码看起来像同步代码
async function fn(){ try{ const data = await getData() }catch(err){ //处理错误 } }
nodejs的事件循环是其核心之一,用于处理非阻塞I/O操作和实现异步编程。事件循环是nodejs单线程特性的关键,事件循环使nodejs能够高效的处理大量的并发请求。
工作原理:
1.初始化,创建三个队列
* Timer队列:setTimeout、setInterval
* Poll队列:文件读写、数据库操作、网络请求
* Check队列:process.nextTick、setImmediate
2.三个队列执行之前,先执行微任务队列,微任务队列执行完成在继续执行事件循环
nodejs的集群化工作模式是利用多核CPU和提升服务器性能的方法。因为nodejs是单线程的,它只能利用一个CPU核心进行工作,所以为了更好的利用多核CPU,nodejs提供了集群模块来创建多个子进程,每个子进程运行在独立的线程上,并独立的处理请求。
在集群化工作模式中,主进程负责管理所有的子进程,子进程可以接收相应客户端请求,并独立的进行处理。
集群化的工作模式,可以提高服务器的吞吐量和响应能力。同时由于每个子进程都是独立的,它们之间不会共享内存或状态,因此可以提高应用程序的稳定性和安全性。
nodejs中的Stream(流)是一种处理的数据的方式,可以处理大量数据。Stream可以以流的方式处理数据,而不是一次性加载所有数据到内存中。可读流、可写流、Duplex流(可读和可写)
适用于构建实时、高并发、基于网络的应用程序,如实时聊天应用、实时数据流应用等。由于nodejs的事件驱动和非阻塞I/0模型,它可以处理大量的并发链接。
EventEmitter:事件发射器,用于对nodejs事件进行统一的管理。
EventEmitter的主要作用是简化事件的创建、订阅、发布等操作,使开发者能够更加方便的处理事件。它通过事件驱动的方式,使得各个模块之间的通信更加灵活和高效。
//events模块中的事件总线 const EventEmitter = require("events") //创建EventEmitter实例 const emitter = new EventEmitter() const fn = (...args) => { console.log("监听事件",args) } //监听事件 emitter.on('aaa',fn) //发射事件 emitter.emit("aaa",1,2,3) //取消事件 emitter.off('aaa',fn)
class EventBus {
constructor() {
this.eventObj = {};
this.calbackId = 0;
}
// 监听事件
on(key, calback) {
if (!this.eventObj[key]) {
this.eventObj[key] = {};
}
const id = this.calbackId++;
this.eventObj[key][id] = calback;
return id;
}
// 发布事件
emit(key, ...args) {
const calbackList = this.eventObj[key];
for (let id in calbackList) {
const cb = this.eventObj[key][id];
cb(...args);
if (id.indexOf("d") > -1) {
delete this.eventObj[key][id];
}
}
}
// 关闭订阅
off(key, id) {
delete this.eventObj[key][id];
if (!Object.keys(this.eventObj[key]).length) {
delete this.eventObj[key];
}
}
// 发射一次事件
once(key, calback) {
if (!this.eventObj[key]) {
this.eventObj[key] = {};
}
const id = "d" + this.calbackId++;
this.eventObj[key][id] = calback;
return id;
}
}
测试代码
const ev = new EventBus();
ev.once("a", (name) => {
console.log("once");
});
const id = ev.on("a", () => {
console.log("a执行111");
});
ev.on("a", (name, age) => {
console.log("a执行", name, age);
});
ev.on("b", () => {
console.log("b执行");
});
ev.emit("a");
ev.off("a", id);
ev.emit("a", 123, 777);
ev.emit("b");
1.启动方式不同。koa使用new Koa(),express使用express()
2.中间件形式。
//express const express = require("express"); const app = express(); app.post( "/login", (req, res, next) => { console.log(1); next(); //执行下一个中间件 }, (req, res, next) => { console.log(2); next(); }, (req, res, next) => { console.log(3); } ); app.listen(8000, () => { console.log("启动成功"); }); //koa const Koa = require("koa"); const app = new Koa(); app.use((ctx, next) => { // 请求对象 console.log(ctx.request); //koa封装的对象 console.log(ctx.req); //node封装的对象 // 响应对象 console.log(ctx.response); //koa封装的对象 console.log(ctx.res); //node封装的对象 console.log(ctx.query); //其他属性 ctx.body = "hhhh"; next(); //执行下一个中间件 }); app.listen(8000, () => { console.log("启动成功"); });
3.异步处理方式。koa通过Generator和async/await使用同步的写法处理异步。express通过回调函数实现异步。
4.路由和试图。express包含完整的应用程序框架,具有路由、模板等功能。koa只有HTTP模块,路由等需要单独引入。
5.错误处理。express使用回调函数捕获错误。koa使用try-catch捕获。
需要使用更多的内置中间件并且对异步处理有更高的要求,Express可能是一个更好的选择。如果希望有更简洁的代码结构并且享受自定义中间件带来的灵活性,那么Koa可能更适合。
- 解析命令,获取模块名。
- 查找模块,npm会在npm注册表中查找。注册表是一个存储了所有公开npm模块和其版本信息的仓库。npm会查找指定模块的最新版本并存储到本地缓存中。
- 解析依赖,npm解析模块的package.json文件,并获取该模块的依赖列表,然后递归的查找这些依赖模块,并在本地缓存中安装。
- 安装依赖,在安装前,会先查找本地缓存,如果有,就使用本地缓存,没有就从npm注册表中下周最新版本的依赖并存储到本地。
- 处理全局安装,如果使用-g/--global,npm会将模块安装到全局安装目录中。
1.npm:nodejs默认的包管理器。安装速度慢。
2.cnpm:淘宝镜像进行安装,速度快;但可能更新不及时。
3.yarn:解决了npm在性能和一致性方面的一些问题。安装速度快。
4.pnpm:通过共享相同的依赖项来减少磁盘空间的占用。硬连接、软连接
Buffer主要用来处理二进制数据。在node中主要用来进行网络协议处理、读取文件等。
.....持续更新中