我正在尝试创建一个阻塞控制流程,但已经走到了尽头。 这个想法是请求进入并流经许多处理函数。每个功能都会执行某些操作,并决定是否现在满足请求。如果是,则处理停止,否则,调用下一个处理程序。 每个处理程序可能会也可能不会异步执行某些操作(如获取/写入数据)。如果是这种情况,那么以下处理程序取决于启动之前的数据。
到目前为止,我有两个想法,它们都不符合这些要求:
1)所有处理程序都是函数,它们被推入一个数组并用some
迭代。如果处理程序希望停止控制流,则只需返回true
。
使用这种方法,我不能让任何处理程序调用异步函数。
2)所有处理程序都是链接的承诺。这对我来说似乎是一个更好的主意,但我无法弄清楚如何最好地处理停止控制流程。我有两个想法:
- 一旦处理程序决定中断流,保留一个设置为true
的变量。在每个处理程序中检查此值,并在需要时立即解决。这意味着很多重复的代码。
- 拒绝承诺,如果它不希望继续正常流程,并继续catch
。但是,使用错误作为控制流程的一种手段的想法让我很痛苦 - 这也意味着我必须处理由于实际错误而调用catch的情况。
我的蜘蛛般的感觉告诉我必须有另一种方式,但我无法弄明白。
答案 0 :(得分:5)
您可以根据需要使用ES6生成器生成承诺。每当一个promise解析它就可以检查一个停止值,如果为false(即继续执行下一个处理程序),则从迭代器中请求下一个。
function* promiseHandlers() {
const handlers = [
promiseHandler1,
promiseHandler2,
promiseHandler3,
promiseHandler4,
promiseHandler5
];
for (const handler of handlers) {
yield handler();
}
}
function run(iter) {
const i = iter.next();
if (i.done) {
return Promise.reject(new Error("end of iterator reached"));
}
return Promise.resolve(i.value).then(result => result || run(iter));
}
run(promiseHandlers());
这实际上不是链接。相反,它将按顺序执行每个promiseHandler,但这些的结果不会传递给下一个。我认为这对OP想要的是正确的,因为一个真实的结果会结束迭代(即休息)。
答案 1 :(得分:3)
不要将承诺处理程序链接起来,嵌套它们。您可以通过一系列函数以编程方式执行此操作:
var handlers = […]; // functions that can return promises
var run = handlers.reduceRight(function(next, handler) {
return function() {
return Promise.resolve(someArg).then(handler).then(function(result) {
if (result) // true, whatever
return result;
else
return next();
});
};
}, function end() {
return Promise.reject(new Error("no handler matched"));
});
run().then(function(result) {
// the result from the first handler that returned anything
}, function(err) {
// some handler threw an exception, or there was no handler
});