Node.js:global(全局变量)
Node 文件顶层能直接写的名字,并不都是「全局变量」。一类挂在进程的全局对象上,每个模块拿到的是同一份;另一类只在当前 CommonJS 文件里有,由模块包装函数当形参注入,换一个文件就是另一套值。把两类混在一起,会把 exports、__dirname 误当成 global 上的属性。
全局变量
真全局属于 整个 Node 进程:语言自带的(如 Object、undefined),以及 Node 挂上去的(如 process、Buffer)。它们是 global(也就是 globalThis)上的属性,任意模块里读到的是同一个对象。
浏览器里脚本顶层就是全局作用域,var something 会挂到全局。Node 的 CommonJS 和 ESM 顶层都不是全局作用域,var something 只在当前模块里。要真正挂到进程全局,应写 global.something 或 globalThis.something。globalThis 在浏览器和 Node 都能用;在 Node 里它就是 global。
往全局挂自定义变量会污染所有模块,应用代码应优先用模块导出。
global
Node.js 的全局命名空间对象。上面说的真全局,都可以写成 global.process、global.Buffer 这种形式,只是平时省略了前缀。
process
描述并控制当前 Node 进程:环境变量、argv、标准流、退出码等。无需 require。ESM 里同样是全局(也可 import process from 'node:process')。
Buffer 类
用来直接处理二进制数据。仍是全局构造器,也可以 require('node:buffer')。不要再用已删除的 new Buffer(),一律 Buffer.alloc、Buffer.from。
Buffer.alloc(size[, fill[, encoding]])Buffer.allocUnsafe(size)Buffer.allocUnsafeSlow(size)Buffer.byteLength(string[, encoding])Buffer.compare(buf1, buf2)Buffer.concat(list[, totalLength])Buffer.from(array)Buffer.from(arrayBuffer[, byteOffset[, length]])Buffer.from(buffer)Buffer.from(string[, encoding])Buffer.isBuffer(obj)Buffer.isEncoding(encoding)Buffer.poolSize
Console 类
console 模块提供调试输出,类似浏览器控制台。
它导出两块:
- Console 类:
log、error、warn等,可以写到任意可写流。 - 全局
console实例:默认写到process.stdout和process.stderr。全局console的方法 既不保证总是同步(和浏览器不同),也不保证总是异步(和其他 Node 流不同)。
可自己指定输出流:
const { Console } = require('console');
// 或者
const { Console } = console;
const logger = new Console(process.stdout, process.stderr);
new Console(stdout[, stderr][, ignoreErrors])console.assert(value[, message][, ...args])console.clear()console.count([label])console.countReset([label])console.debug(data[, ...args])console.dir(obj[, options])console.error([data][, ...args])console.group([...label])console.groupCollapsed()console.groupEnd()console.info([data][, ...args])console.log([data][, ...args])console.time(label)console.timeEnd(label)console.trace([message][, ...args])console.warn([data][, ...args])
setImmediate(callback[, ...args])
把 callback 排进事件循环的 check 阶段。同一轮里多次 setImmediate 按登记顺序跑完这一轮队列。若在 正在执行的 immediate 回调里 再 setImmediate,要等到 下一轮 check。
setTimeout(fn, 0) 看起来很像,但走的是 timers 阶段。Node 会把小于 1 的 delay 当成 1 毫秒。两者谁先跑,取决于调用时所在的阶段:
- 在文件 I/O、网络 I/O 等回调里:本轮会先进入 check,
setImmediate先于setTimeout(fn, 0)(浏览器事件循环不是这套,不要套过来)。
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('1');
}, 0);
setImmediate(() => {
console.log('2');
});
});
// 2
// 1
- 在主模块同步代码里:两个都只是「排期」,顺序不固定。timers 的 1ms 到了没、以及何时离开 poll,都会影响结果。
setTimeout(() => {
console.log('1');
}, 0);
setImmediate(() => {
console.log('2');
});
// 顺序不固定
clearImmediate(immediate)
取消 setImmediate() 返回的 Immediate。
setInterval(callback, delay[, ...args])
每隔 delay 毫秒重复执行 callback。
delay 大于 2147483647 或小于 1 时按 1 处理;非整数会截成整数。
clearInterval(timeout)
取消 setInterval() 返回的 Timeout。
setTimeout(callback, delay[, ...args])
大约在 delay 毫秒后执行一次 callback。Node 不保证刚好在那一毫秒触发,也不保证和别的定时器的先后,只保证尽量靠近指定时间。
delay 大于 2147483647 或小于 1 时按 1 处理;非整数截成整数。
clearTimeout(timeout)
取消 setTimeout() 返回的 Timeout。
注意: Node 里 setImmediate、setInterval、setTimeout 返回的是 对象;浏览器里返回的是正整数编号。
其他现行全局
这些同样是进程级的,不是包装函数注入的:
globalThis、queueMicrotaskURL、URLSearchParams、TextEncoder、TextDecoder、AbortController、Blob、Event、EventTargetfetch、Headers、Request、Response(Node 18 起默认可用)structuredClone、performance(perf_hooks那套时间原点)crypto作为 Web Crypto 全局(与require('node:crypto')不是同一个模块对象,但经常一起出现)
模块包装函数注入的名字
CommonJS 加载一个 .js 文件时,不会把文件当全局脚本跑,而是包进一个函数再调用。五个形参就是下面这些名字:
(function (exports, require, module, __filename, __dirname) {
// 当前文件的源码在这里执行
});
因此它们 不是 global 上的属性,只在 当前这个 CJS 文件 的作用域里有效。换一个文件,包装函数会再调一次,五个参数换成那份文件自己的。
console.log(global.require); // undefined
console.log(typeof require); // 'function',来自包装函数形参
ESM("type": "module" 或 .mjs)没有这层包装,也就没有这五个名字。目录和文件名用 import.meta.dirname、import.meta.filename(Node 20.11+),或用 import.meta.url 自己算:
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
加载别的模块用 import;需要 CJS 的 require 时再用 createRequire(import.meta.url)。