返回介绍

Advanced Asynchronous Recipes

发布于 2025-01-25 22:50:10 字数 2497 浏览 0 评论 0 收藏 0

这一章主要讲了三种书写异步的常见模型:

  • 异步引入模块并初始化
  • 在高并发的应用程序中使用批处理和缓存异步操作的性能优化
  • 运行与 Node.js 处理并发请求的能力相悖的阻塞事件循环的同步 CPU 绑定操作

异步初始化模块

如果一个 Node.js 模块需要异步初始化,可以有以下两种解决方案:一是在开始使用模块之前之前确保模块已经初始化,否则则等待其初始化。二是使用预初始化队列进行初始化,在初始化之前的所有操作均放入预初始化队列中,等待初始化完成后取出队列中的任务。

  • 等待初始化
// 模块 app.js
const db = require('aDb'); // aDb 是一个异步模块
const findAllFactory = require('./findAll');
db.on('connected', function() {
  const findAll = findAllFactory(db);
  // 之后再执行异步操作
});


// 模块 findAll.js
module.exports = db => {
  //db 在这里被初始化
  return function findAll(type, callback) {
    db.findAll(type, callback);
  }
}
  • 预初始化队列
const asyncModule = module.exports;

asyncModule.initialized = false;
asyncModule.initialize = callback => {
  setTimeout(() => {
    asyncModule.initialized = true;
    callback();
  }, 10000);
};

asyncModule.tellMeSomething = callback => {
  process.nextTick(() => {
    if(!asyncModule.initialized) {
      return callback(
        new Error('I don\'t have anything to say right now')
      );
    }
    callback(null, 'Current time is: ' + new Date());
  });
};

批处理和缓存

对于接口请求量较大的 API,我们可以使用批处理或者缓存来提升接口性能:批处理指的是在调用异步函数的同时在队列中还有另一个尚未处理的回调,我们可以将回调附加到已经运行的操作上,而不是创建一个全新的请求。缓存不只可以是内存中的变量,还可以是数据库,甚至是专门的缓存服务器。此外,使用缓存需要有一定的策略对缓存进行淘汰,例如 LRU。

CPU-bound 任务

对于运算量较大的同步的 CPU-bound 任务,可能造成接口的阻塞。解决方案有两种:一种是使用异步来包装同步的 CPU-bound 任务,二是使用多进程,一般来说使用 Node.js 子进程,因为 Node.js 自带子进程模块,并且可以使用相关接口进行父子进程的管道通信,而如果子进程不是 Node.js 进程,一般只能通过标准输入输入来进行父子进程的通信。

如何父子进程进行通信:

const EventEmitter = require('events').EventEmitter;
const ProcessPool = require('./processPool');
const workers = new ProcessPool(__dirname + '/subsetSumWorker.js', 2);

class SubsetSumFork extends EventEmitter {
  constructor(sum, set) {
    super();
    this.sum = sum;
    this.set = set;
  }

  start() {
    workers.acquire((err, worker) => {  // [1]
      worker.send({sum: this.sum, set: this.set});

      const onMessage = msg => {
        if (msg.event === 'end') {  // [3]
          worker.removeListener('message', onMessage);
          workers.release(worker);
        }

        this.emit(msg.event, msg.data);  // [4]
      };

      worker.on('message', onMessage);  // [2]
    });
  }
}

module.exports = SubsetSumFork;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文