我有一个现有的 API,它运行一个需要一些时间的任务,然后在作业完成时使用 EventEmitter
发出一个事件。出于我们的目的,我们可以假设它看起来像这样。
const { EventEmitter } = require('events');
class Example extends EventEmitter {
longRunningJob() {
// Assume some long-running task is happening here...
setTimeout(() => {
this.emit('job_completed');
}, 1000);
}
}
现在,我正在编写一个 async
函数,我想按顺序执行几个这样的任务。一种幼稚的方法可能是
const example = new Example();
console.log("Starting jobs...");
example.longRunningJob();
example.once('job_completed', () => {
console.log("One");
example.longRunningJob();
example.once('job_completed', () => {
console.log("Two");
example.longRunningJob();
example.once('job_completed', () => {
console.log("Done :)");
});
});
});
但是这与促使我们发明 async
/ await
的可读性问题相同。因此,尝试将这种方法包装在某种 Promise
中是有意义的,我已经完成了如下操作。
const onEvent = function(obj, eventName) {
let resolve;
const promise = new Promise(function(res, rej) { resolve = res; });
obj.once(eventName, function() { resolve(); });
return promise;
};
const example = new Example();
console.log("Starting jobs...");
example.longRunningJob();
await onEvent(example, 'job_completed');
console.log("One");
example.longRunningJob();
await onEvent(example, 'job_completed');
console.log("Two");
example.longRunningJob();
await onEvent(example, 'job_completed');
console.log("Done :)");
我们已经修复了“失控缩进”的问题,但这仍然不能让我很满意。 onEvent
是变异变量和让 Promise 解析函数逃避范围的混乱组合,这感觉很脆弱。此外,这感觉像是一个并不少见的问题:等待特定事件的愿望。所以我的问题是 (a) 此功能是否以更强大的方式内置到 Node 中,以及 (b) 如果不是,是否有更强大、更少被黑客攻击的方式来等待特定事件?
答案 0 :(得分:0)
一种简化是立即返回 Promise 而不是首先分配给外部 resolve
变量:
const onEvent = (obj, eventName) => new Promise((resolve) => {
obj.once(eventName, resolve);
};
您也可以使用循环代替多次写出 onEvent
和 longRunningJob
:
const example = new Example();
console.log("Starting jobs...");
for (let i = 0; i < 3; i++) {
example.longRunningJob();
await onEvent(example, 'job_completed');
console.log(i);
}
console.log('done');
如果可能,还可以考虑将 Example
更改为返回 Promise 而不是使用回调的方法:
const example = new Example();
console.log("Starting jobs...");
for (let i = 0; i < 3; i++) {
await example.queueJob();
console.log(i);
}
console.log('done');
这确实是目前最好的解决方案(让该方法返回一个在工作完成时解析的 Promise),但如果它是第 3 方 API,则可能无法更改其代码。