Node.js

· 1546 words · 4 minute read

what 🔗

Node.js 是基于 V8 引擎的 JavaScript 运行时,让你可以用 JavaScript 写后端服务、命令行工具、爬虫、中间件等等。 特点:Node.js 上手快,社区生态非常强大(npm)。

核心模块 🔗

node.js 内置的模块,无依赖即可用。

模块 用途
fs 文件读写
path 路径处理
http/https 创建 Web 服务
url 处理 URL 路径
events 事件系统(重要)
child_process 启动子进程
os 获取系统信息

模块机制 + 异步模型 🔗

知识点 说明
CommonJS 模块机制 requiremodule.exports
异步编程模型 回调、Promise、async/await
事件循环(Event Loop) Node 的核心运行机制

建议多写几个异步 I/O 实验,如定时器、读文件、异步请求等

node.js 的源码学习 🔗

从 Node 核心模块开始,了解事件驱动模型,理解架构组成,再深入 libuv、V8 和 C++ 层源码,边读边调试、边做实验。

  • 熟练掌握 JavaScript(包含 ES6+)
  • 理解 Node 核心模块(fs、http、events、stream、buffer、process...)
  • 掌握异步编程模型(Promise、Event Loop、async/await)
  • 熟悉一点 C/C++ 语法(建议)
  • 会使用 Git 和 GDB / lldb 调试器(进阶时用)
┌──────────────┐
│ 用户 JS │ JavaScript 层
└─────▲────────┘
│
┌─────┴────────┐
│ Node Bindings│ C++/JS 交互层(如 fs, net)
└─────▲────────┘
│
┌─────┴────┐ ┌───────────────┐
│ libuv │◄──┤ 操作系统 API │ 异步 I/O、多线程抽象层
└─────▲────┘ └───────────────┘
│
┌─────┴────┐
│ V8 │ JS 引擎:执行 JS,管理内存
└──────────┘

搭建源码阅读环境 🔗

git clone https://github.com/nodejs/node.git
cd node
./configure
make -j4
./node  # 编译成功

核心概念 🔗

运行时环境 v8

事件循环, 实现非阻塞 io,处理异步操作

六个阶段(按顺序执行)

  • timer, 执行 setTimeout, setInterval
  • pending,
  • idle, prepare
  • poll
  • check, 执行 setImmediate
  • close callback,

非阻塞 io 与 libuv。

单线程模型: js 主线程执行同步代码,异步操作有 libuv 交给线程池处理,完成后通过事件循环通知主线程。

模块化机制 CommonJS 🔗

module.exports 和 require 具体在做什么吗?

node.js 中的 require 是 CommonJS 模块规范的实现。

当调用 require 时,node 会按优先级顺序进行模块位置的搜索。模块的查找

  • 内置模块(fs, path)
  • 路径模块
    • ./, ../ 直接按路径查找文件
    • 是模块名时,从当前目录的node_modules开始,逐级查找 node_modules 时直到根目录。
  • 文件后缀补全
    • 会按.js, .json, .node(c++扩展模块)的顺序补全后去查找
  • 目录模块处理
    • 优先读取 package.json 的 main 字段指定的入口文件

模块编译。模块里的代码会包裹在一个函数中。

(function (exports, require, module, __filename, __dirname) {
  const a = 1;
  module.exports = a;
})(exports, require, module, filename, dirname);

模块缓存。

require.cache = {
  '/path/to/module.js': {
    id: '/path/to/module.js',
    exports: {},
    loaded: true,
  },
  {...}
}

module 是每个模块自带的对象。 module.exports 是模块的默认导出接口, exports 是 module.exports 的引用。 如果直接给 exports 赋值,如 exports={a: 1},则会切断与 module.exports 的关联。

require 和 package.json 配置的密切关系 🔗

package.json 中的 main 字段定义了当前包(模块)被 require 时的默认入口文件。

若 node_modules/foo/package.json 中配置:{ "main": "lib/foo.js" }。 则 require('foo') 等价于 require('./node_modules/foo/lib/foo.js')。

export字段是比 main 更强大的配置,用于限制模块的可访问路径。

{
  "exports": {
    ".": "./index.js", // require('foo') 加载 index.js
    "./util": "./lib/util.js", // require('foo/util') 加载 lib/util.js
    "./feature": {
      "node": "./feature/node.js", // Node.js 环境加载此文件
      "default": "./feature/browser.js"
    }
  }
}

除了 main 字段和 exports 字段,package.json 还有哪些字段会影响 require 的行为?

type 字段:影响 .js 文件的解析方式,决定模块系统类型 common js or es module。

module 字段:工具链的 ESM 入口。被 Webpack、Rollup 等构建工具广泛使用,用于指定 ES 模块的入口文件。 browser 字段:浏览器环境的模块映射(工具链使用)。

常见的框架 🔗

express(Web)、axios(请求)、moment(时间)

配合使用的数据库 🔗

Mysql, Progres, mongodb。

《深入浅出 Node.js》(进阶必读)