- Welcome to the Node.js Platform
- Node.js Essential Patterns
- Asynchronous Control Flow Patterns with Callbacks
- Asynchronous Control Flow Patterns with ES2015 and Beyond
- Coding with Streams
- Design Patterns
- Writing Modules
- Advanced Asynchronous Recipes
- Scalability and Architectural Patterns
- Messaging and Integration Patterns
- Welcome to the Node.js Platform
- Node.js 的发展
- Node.js 的特点
- 介绍 Node.js 6 和 ES2015 的新语法
- reactor 模式
- Node.js Essential Patterns
- Asynchronous Control Flow Patterns with Callbacks
- Asynchronous Control Flow Patterns with ES2015 and Beyond
- Coding with Streams
- Design Patterns
- Writing Modules
- Advanced Asynchronous Recipes
- Scalability and Architectural Patterns
- Messaging and Integration Patterns
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
Advanced Asynchronous Recipes
这一章主要讲了三种书写异步的常见模型:
- 异步引入模块并初始化
- 在高并发的应用程序中使用批处理和缓存异步操作的性能优化
- 运行与
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论