7-1 nodejs 基础

75 阅读6分钟

服务器主要处理的是 I/O(输入/输出) 请求

简介

基础模块

1、fs:File System,操作文件的 (常用)

2、path:操作路径的(不常用)

3、http:创建 http 服务器的,处理客户端请求 (常用)

4、net:底层网络通信模块(不常用)

5、process:进程管理 (常用)


V8 核心:事件循环、内存原理

Node 版本管理工具:nvm(必装的)

使用 http 起一个简单的 server:

  1. 创建文件夹
mkdir base && cd base && touch index.js && pnpm init
  1. 写入代码
// 引入 http 模块
const http = require("http");

// 创建一个 HTTP 服务器
const server = http.createServer((req, resp) => {
  // 从请求对象中获取请求方法和请求 URL
  const { method, url } = req;

  // 设置响应头的 Content-Type 为 "text/html; charset=utf-8"
  resp.setHeader("Content-Type", "text/html; charset=utf-8");
  // 设置响应状态码为 200
  resp.statusCode = 200;
  // 发送响应内容,并结束响应
  resp.end(
    `<h1>hello,我是使用 http 创建的服务器,你是一个:${method} | ${url}</h1>`
  );
});

// 从环境变量中获取端口号,如果没有则使用默认值 3001
const port = process.env.PROT || 3001;

// 启动服务器并监听指定端口
server.listen(port, () => {
  // 打印服务器运行信息
  console.log(`HTTP Server running on http://localhost:${port}`);
});
  1. 运行node index.jsornodemon index.js

nodemon:一个 Node.js 开发工具,用于监视项目文件的变化,并在检测到变化时自动重启 Node.js 应用。

安装npm install -g nodemon

字符集

字符集:它定义了一组符号和编码规则,用于表示文本中的字符。

写一个读取文件的 js

  1. 创建文件:fs.js
touch fs.js
  1. 写入代码:
const fs = require("fs");

const path = require("path");

function getFile(filePath) {
  try {
    const fileContent = fs.readFileSync(path.resolve(__dirname, filePath));
    const fileContentUtf8 = Buffer.from(fileContent).toString("utf8");
    console.log("[ fileContent ] >", fileContent);
    console.log("[ fileContentUtf8 ] >", fileContentUtf8);
  } catch (error) {
    console.log("[ getFile error ] >", error);
  }
}
getFile("./package.json");
  1. 运行node fs.js

readFileSync默认读取到的文件会以Buffer展示

Buffer是 nodejs 中处理二进制数据的类,可将其转为不同字符编码(utf8/base64/ascii 等)的数据。Buffer.from('原内容').toString('编码')

Buffer 类

const Buffer = require('buffer')

Buffer.alloc(size[, fill[, encoding]]) // 指定容量创建空 Buffer(已初始化的)
Buffer.allocUnsafe(size[, fill, ]) // 指定容量创建空 Buffer(未初始化的),所以不安全

Buffer.from(str[, encoding]) // 从已有数据创建 Buffer

Base64

base64 组成:小写 a-z,大写 A-Z,数字 0-9,符号 “+”“/”共 64 个字符(额外还有个“=”符号)

将字符串(图片等)转为二进制序列(010101...),然后每 6 个为一组进行分组,不足 6 个的低位补 0。分完组后,每6 个组成新的字节,高位补00,构成新的二进制序列,然后转为十进制,最后在 base64 索引表中找该十进制对应的字符

  1. 一个字节 = 8比特(bit),是由 8 个二进制位组成的,其范围是从二进制的00000000到11111111,转换为十进制就是0到255。

  2. ASCII字符集中的英文字符及其他一些符号可以用一个字节表示,因为ASCII字符集总共只有128个字符(0到127),小于一个字节所能表示的最大范围。

  3. 对于中文字符,以及其他许多非ASCII字符,由于字符数量众多,通常需要使用两个字节来表示。

Process

提供当前 nodejs 进程相关的信息

process.env当前用户环境信息

{
    USER: 'hzq',
    PATH: '/Users/hzq/xxxx',
    PWD: '/Users/hzq/code/mianshi/7-1 nodejs 基础/nodejs-base',
    HOME: '/Users/hzq',
    _: '/Users/hzq/.nvm/versions/node/v16.14.0/bin/node'
    // .....
}

process.cwd()返回当前 nodejs 进程的工作目录

process.cwd() // /Users/hzq/code/7-1 nodejs 基础/nodejs-base

Crypto

在 Node.js 中,crypto 模块是内置的加密和解密库,提供了丰富的密码学相关的功能,包括哈希(Hashing)、消息认证码(MACs)、加密(Encryption)、解密(Decryption)、签名(Signing)和验证(Verification)等。以下是 crypto 模块中一些常见用法:

  1. 哈希(Hashes) : 
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
hash.update('some data to hash');
const digest = hash.digest('hex'); // 得到哈希摘要
  1. HMAC(哈希消息认证码) : 
const hmac = crypto.createHmac('sha256', 'secret key');
hmac.update('message');
const hmacDigest = hmac.digest('hex');
  1. 对称加密(Symmetric Encryption) : 
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32); // 生成一个密钥
const iv = crypto.randomBytes(16); // 生成一个初始化向量(IV)

// 加密
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update('message', 'utf8', 'hex');
encrypted += cipher.final('hex');

// 解密
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
  1. 非对称加密(Asymmetric Encryption) : 
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
  modulusLength: 2048,
});

// 加密
const encrypted = crypto.publicEncrypt(publicKey, Buffer.from('message'));

// 解密
const decrypted = crypto.privateDecrypt(privateKey, encrypted);
  1. 签名(Signatures) : 
const sign = crypto.createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');

// 验证签名
const verify = crypto.createVerify('SHA256');
verify.write('some data to sign');
verify.end();
const isVerified = verify.verify(publicKey, signature, 'hex');

Http1.x VS Http 2

1、传输格式:1.x 使用文本格式;2 使用二进制格式(更高效)

2、多路复用:1.x 一次 TCP 连接只能发送一次请求;2 可一次 TCP 连接发送多次请求(耗时更少),

3、服务器推送:1.x 不支持服务器主动推送内容给客户端;2 就支持

V8

事件循环

nodejs 端的事件循环跟浏览器端的有点不一样。

浏览器端的事件循环主要服务于UI 渲染和网络请求

nodejs 端的事件循环主要服务于 IO 处理、定时器、异步任务等

node 的宏任务、微任务

常见宏任务:I/O callbacks、timer(settimeout、setInterval)、setImmediate

常见微任务:Promise 回调、process.nextTick 等

循环流程:

1、入口进入,作为第一个宏任务被执行

2、执行同步代码直到结束

3、清空微任务列表,若有新的微任务产生,则继续清空

4、检查是否进行 I/O Poll 阶段

5、执行下一个宏任务

内存管理

在服务端内存是比较珍贵的,nodejs 限制了 64 位机器最大为 1.4 GB,限制了 32 位机器最大为 0.7GB

管理过程:

采用 GC:Garbage Collection - 垃圾回收 来管理内存

1、标记:通过遍历GC Root来标记活动或非活动对象,遍历到的就是活动的,不能遍历到的就是非活动的

2、清除:将非活动对象清除

内存划分

堆:复杂类型;栈:基本类型;

分代垃圾回收

针对“堆”,划分了两个区域:新生代、老生代

新生代(存放短、容量小):

新创建的先放这里面。

采用 Scavenge 算法,又分为 FromTo 区域

新创建先放 From 区域,当 From 区域满时,进行垃圾回收(标记清除) ,然后把存活的复制到 To 区域,之后翻转一下,即 From 变为 ToTo 变成 From,之后重复直到两次垃圾回收(标记清除) 后还存在的就移动到老生代中

老生代(存放久,容量大):

多次在新生代里面存活的就晋升为老生代。

垃圾回收采用的是标记-清除标记-整理

标记-整理: 基于标记清除,然后再整理了下内存碎片