Node.JS 记录合集

process.hrtime

process.hrtime

process.hrtime() 是一个在 Node.js 中可用的全局方法,它返回一个表示当前时间的高分辨率时间戳。时间戳表示为一个包含两个元素的数组。第一个元素是以秒为单位的时间戳,而第二个元素是以纳秒为单位的时间戳。

这个函数的特点是它可以提供非常高的时间测量精度,远超过常规的 Date.now() 或者 new Date().getTime() 这样的 JavaScript 方法。它特别适用于需要精确测量代码执行时间的情况。

它的另一个特点是它是基于启动 Node.js 进程的时间的,而不是基于 Unix 纪元(1970年1月1日00:00:00 UTC)的。这意味着它不受系统时间变化的影响,例如由于网络时间同步或者用户手动更改系统时间。

如果你传递一个以前 process.hrtime() 返回的时间戳作为参数给这个函数,它会返回两个时间戳之间的时间差。这对于测量代码块的执行时间非常有用。例如:

javascript
1var startTime = process.hrtime();
2// 一些需要测量执行时间的代码...
3var diffTime = process.hrtime(startTime);
4console.log(`执行时间:${diffTime[0] * 1e9 + diffTime[1]}纳秒`);

在这个例子中,diffTime[0] 是时间差的秒部分,diffTime[1] 是时间差的纳秒部分。将它们加起来得到的是以纳秒为单位的总执行时间。

async_hooks

async_hooks 是 Node.js 的一个核心模块,主要用于跟踪异步资源的生命周期。这对于诊断和分析异步行为非常有用,尤其是在复杂的、高度异步的应用程序中。以下是一些 async_hooks 的主要用途和特点:

  1. 跟踪异步操作的执行上下文:通过 async_hooks,开发者可以跟踪异步操作的创建、销毁、触发和继承等。这有助于理解异步资源(例如 Promise、回调、定时器等)如何随着应用程序的运行而改变。
  2. 诊断和调试async_hooks 可以用于构建更复杂的诊断工具,以便于识别和解决潜在的异步问题。例如,开发者可以使用它来检测内存泄漏或异步操作之间的不一致。
  3. 性能监控和分析:通过对异步操作的跟踪,可以分析它们的执行时间和频率。这有助于识别潜在的性能瓶颈或资源使用不足的区域。
  4. 上下文传播:在分布式系统或微服务体系结构中,有时需要跟踪在多个异步调用和服务之间传播的上下文。async_hooks 可以用于实现上下文传播,以确保跨服务的请求具有一致的上下文信息。
  5. 创建自定义监控和追踪工具async_hooks 可以用作构建定制的监控和追踪工具的基础,以适应特定的业务需求和应用程序特性。

下面是一个使用 async_hooks 的简单示例,用于打印异步资源的生命周期事件:

javascript
1const async_hooks = require('async_hooks');
2
3const hook = async_hooks.createHook({
4  init(asyncId, type, triggerAsyncId) {
5    console.log(`Init: ${asyncId}, type: ${type}, trigger: ${triggerAsyncId}`);
6  },
7  destroy(asyncId) {
8    console.log(`Destroy: ${asyncId}`);
9  }
10});
11
12hook.enable();

总体而言,async_hooks 是一个强大的工具,用于分析和理解异步操作在 Node.js 应用程序中的行为。不过,它还是相对低级的 API,通常用于工具和库的开发,而不是直接用于日常的应用程序开发。

cls-hooked

直接使用 async_hooks 可能会稍微复杂,特别是在大型项目中。有一些第三方库可以帮助简化此过程,例如 cls-hooked,它提供了更高级别的抽象来处理上下文本地存储。

使用 cls-hooked 来管理请求的上下文可以使代码更加简洁和直观。以下是一个使用 Express 和 cls-hooked 来跟踪每个请求 requestId 的示例。

  1. 安装所需的依赖项

    bash
    1npm install express uuid cls-hooked
  2. 编写代码

    javascript
    1const express = require('express');
    2const { v4: uuidv4 } = require('uuid');
    3const cls = require('cls-hooked');
    4
    5const app = express();
    6const port = 3000;
    7
    8// 创建名为 'request' 的命名空间
    9const requestNamespace = cls.createNamespace('request');
    10
    11// 中间件:为每个请求分配 requestId 并存储在命名空间中
    12app.use((req, res, next) => {
    13  requestNamespace.run(() => {
    14    const requestId = uuidv4(); // 生成唯一的 requestId
    15    requestNamespace.set('requestId', requestId);
    16    next();
    17  });
    18});
    19
    20app.get('/', (req, res) => {
    21  const requestId = requestNamespace.get('requestId'); // 获取当前请求的 requestId
    22  console.log(`Handling request, requestId: ${requestId}`);
    23  res.send(`Your request ID is: ${requestId}`);
    24});
    25
    26app.listen(port, () => {
    27  console.log(`Server running at http://localhost:${port}/`);
    28});
  3. 测试运行

    运行服务器并访问 http://localhost:3000/,每个请求将在控制台输出其 requestId,并在响应中返回它。

cls-hooked 通过创建命名空间并在该命名空间内运行中间件函数来实现上下文本地存储。在命名空间的上下文中,你可以使用 setget 方法来存储和检索与当前请求相关的信息。在上面的示例中,我们创建了一个名为 request 的命名空间,并在其中存储了每个请求的 requestId

这种方法的好处是它隐藏了 async_hooks 的复杂性,使你能够更容易地管理和操作请求上下文。在更大型和复杂的应用程序中,可以使用同样的模式来存储和管理跨异步操作的任何类型的上下文信息。

nodejs 中 writeFileSync 在父级目录不存在的情况下会报错

在 Node.js 中,fs.writeFileSync() 方法假定指定路径的父目录已经存在。如果父目录不存在,该方法将抛出一个错误。例如,假设您尝试写入一个文件,而其父目录尚未创建:

javascript
1const fs = require('fs');
2
3fs.writeFileSync('nonexistent_directory/file.txt', 'Hello, world!');

上述代码会导致以下类型的错误:

perl
1Error: ENOENT: no such file or directory, open 'nonexistent_directory/file.txt'

要解决此问题,您可以使用 fs.mkdirSync() 方法预先创建父目录,或者使用第三方库(如 mkdirp)来递归地创建所有必要的父目录。以下是一个使用 fs.mkdirSync() 的示例:

javascript
1const fs = require('fs');
2const path = require('path');
3
4const dir = 'nonexistent_directory';
5const filePath = path.join(dir, 'file.txt');
6
7// 创建目录,如果它不存在
8if (!fs.existsSync(dir)) {
9    fs.mkdirSync(dir);
10}
11
12// 现在可以安全地写入文件
13fs.writeFileSync(filePath, 'Hello, world!');

该方案确保了父目录存在,然后再执行 fs.writeFileSync(),从而避免了错误。需要注意的是,这个解决方案没有处理并发问题或其他潜在的文件系统相关的异常状况。在生产环境中,更全面的错误处理机制是必要的。

优雅解决办法

第三方库通常提供更高级的功能,包括在写入文件时自动创建不存在的父目录。一个流行的库是fs-extra,它是对Node.js原生fs模块的一个扩展。

以下是使用fs-extra库的一个简单示例:

javascript
1const fs = require('fs-extra');
2const path = require('path');
3
4const dir = 'nonexistent_directory';
5const filePath = path.join(dir, 'file.txt');
6
7// 使用 ensureFile 方法确保父目录存在
8fs.ensureFile(filePath)
9  .then(() => {
10    fs.writeFileSync(filePath, 'Hello, world!');
11  })
12  .catch(error => {
13    console.error(error);
14  });

在这个示例中,ensureFile方法会自动创建文件以及其所有不存在的父目录。一旦确保文件和目录存在,您便可以安全地使用writeFileSync方法写入文件。

使用这样的第三方库可以简化代码,并减少手动错误处理的需要,从而提高代码的健壮性和可维护性。