跳到主要内容

Node

简介

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。

简单说,node 就是一个可以运行 JavaScript 代码的环境,不是一门编程语言,可以做服务端开发。

  1. node 运行的 js 是指 ECMAScript,不能运行 BOM 和 DOM 的 API(如windowdocument等对象),可以使用 console 和定时器等
  2. node 中的顶级对象是global,也可以使用globalThis(是 ES2020 支持的)

特点

  • 单线程
  • 异步式 I/O
  • 事件驱动
  • 跨平台

这里的单线程是指主线程是单线程的,主线程还能有其他子线程。因为是单线程,所以只要有一个任务耗时非常长,后面的任务必须要排队等待,会拖延整个程序执行,从而降低了效率,于是提出了异步的思想。在执行代码的时候,主线程从上往下依次执行,遇到有需要回调的地方,就将此处加入到事件队列中,然后主线程继续往下走,直到运行结束以后,才去执行事件队列中的回调。

事件驱动是指在持续事务管理过程中,进行决策的一种策略,即跟随当前时间点上出现的事件,调动可用资源,执行相关任务,使不断出现的问题得以解决,防止事务堆积。

模块化写法

  • Node.js 支持 CommonJS 和 ES Module 规范
  • 所有模块操作都具有同步、回调和基于 Promise 的形式
  • 从 Node.js 12.9.0 开始,引入了 node: 前缀来明确表示核心模块,避免与其他模块发生命名冲突。

模块引入方式

以文件系统 fs 模块为例:

1、CommonJS 规范的模块引入方式:

// 原始写法
const fs = require('fs');

// 回调、同步
const fs = require('node:fs');

// 基于 Promise
const fs = require('node:fs/promises');

// 解构
const { readFile } = require('node:fs');
const { readFile } = require('node:fs/promises');

2、ESM 规范的模块引入方式:

import * as fs from 'node:fs';

import * as fs from 'node:fs/promises';

import { readFile } from 'node:fs/promises';

模块使用方式

1、回调函数

const { readFile } = require('node:fs');

readFile('./1.js', { encoding: 'utf-8' }, (err, data) => {
if (err) throw err;
console.log(data);
});

2、同步

const fs = require('node:fs');

const data = fs.readFileSync('./1.js', { encoding: 'utf-8' });

3、Promise

const { readFile } = require('node:fs/promises');

try {
readFile('./1.js', { encoding: 'utf-8' }).then(data => {
console.log(data);
});
} catch (error) {
console.log(error);
}

使用 async/await:

const { readFile } = require('node:fs/promises');

async function getFileContent() {
try {
const data = await readFile('./1.js', { encoding: 'utf-8' });
console.log(data);
} catch (error) {
console.log(error);
}
}
getFileContent();

Node 的执行方式

1、创建一个 JS 文件,在里面写代码,然后通过 node 命令执行。如:node index.js

2、通过使用 Node.js 提供的 REPL(Read-Eval-Print Loop)环境来实现。REPL 是一个交互式编程环境,允许你输入代码、立即执行并看到结果。具体操作是在终端输入 node 并按下回车键,然后就可以编写代码了:

> 1 + 2
3

结束后可以使用control + D 或者输入 .exit 退出 REPL 环境。

3、可以在终端使用 node -e "命令" 直接执行代码。

node -e "console.log('hello world')"

Node 命令

# 查看node版本
node -v

# 查看npm版本
npm -v

# 查看node安装目录
which node

# 查看官方所有的node版本
npm view node versions

管理 node 版本

在维护一些老项目时通常需要降低 node 的版本,如遇到 node-gyp 报错、node-sass 报错等。

node 和 node-sass 对应版本: https://www.npmjs.com/package/node-sass

使用 n 模块管理

https://github.com/tj/n

# 清除npm缓存
sudo npm cache clean -f

# 全局安装 n 模块
sudo npm install -g n

# 查看是否安装成功
n -V

# 查看已安装的node版本
n ls

# 安装指定版本,如 14.12.0
sudo n 14.12.0

# 更新node到最新的稳定版
sudo n stable

# 更新node到最新版本
sudo n latest

# 切换版本,输入 n 回车,上下键选择版本,回车安装
sudo n

# 删除指定版本,如 14.12.0,删除后用 n 切换一下版本
sudo n rm 14.12.0

# 卸载 n
sudo npm uninstall n -g

require 载入模块

Node.js 默认是使用CommonJS规范

  • require 方法用来载入模块的
  • moule.exports 用来导出模块的
提示

在某个文件中写入:console.log(arguments),会发现 CommonJS 的模块是一个立即执行函数,打印结果有 5 个参数:

  1. 第一个参数是{}: exports 对象,module.exports
  2. 第二个参数是是 require 方法,用于载入模块
  3. 第三个参数是是 module 对象
  4. 第四个参数是 __filename: 当前模块的绝对路径
  5. 第五个参数是 __dirname: 当前模块所在目录的绝对路径
console.log(exports == module.exports); // true

载入系统模块和第三方模块不需要写路径,直接写名称即可,但是载入自定义模块需要写路径

const http = require('http');

const myapp = require('../com/my.js');

require 加载第三方包的机制:

  1. 第三方包安装好后,这个包一般会存放在当前项目的 node_modules 文件夹中。找到这个包的 package.json 文件,并且找到里面的 main 属性对应的入口模块,这个入口模块就是这个包的入口文件
  2. 如果第三方包中没有找到 package.json 文件,或者没有 main 属性,则默认加载第三方包中的 index.js 文件
  3. 如果在 node_modules 文件夹中没有找到这个包,或者以上所有情况都没有找到,则会向上一级父级目录下查找 node_modules 文件夹,查找规则如上一致
  4. 如果一直找到该模块的磁盘根路径都没有找到,则会报错:can not find module xxx

第三方模块

  • nodemon 监听 Node 程序中的任何更改并自动重新启动服务器,即热更新
  • csvtojson CSV 格式转为 JSON
  • randomjson 生成随机 JSON 数据
  • http-proxy-agent HTTP(s) 代理 HTTP.Agent 实现 HTTP
  • multiparty 解析具有multipart/form-data类型的 HTTP 请求,如解析上传文件
  • dotenv 从 .env 文件中加载环境变量