当事件在函数内触发时,拒绝异步函数的“首选”方式是什么?
我目前通过用Promise.race
包装每个异步操作来做到这一点:
async function exampleFunction(emitter){
let lastError;
emitter.once('error',error=>lastError=error);
function createCancellable(promise){
//cancel if any error occurred in between
if(lastError)throw new Error(lastError);
//race between the promise, and the next error occurring
let _callback;
return Promise.race([
promise,
new Promise((resolve, reject) =>{
emitter.on('error', _callback = reject);
}),
]).finally(() => {
//cleanup
if (_callback)
emitter.removeListener('error', _callback);
});
}
//actual code
await createCancellable(someAsyncFunction());
await createCancellable(anotherAsyncFunction());
}
是否有更好/更简洁的方法?
答案 0 :(得分:3)
我认为没有其他方法可以执行您要说的话,因为从根本上说,您在每个阶段都需要在两个诺言之间进行竞赛(事件发射器的错误以及您所做的确实在做)。
但是它可能要简单得多,这可能会使它更美味:
async function exampleFunction(emitter){
const pError = new Promise((_, reject) => {
emitter.once('error', reject);
});
const createCancellable = promise => Promise.race([pError, promise]);
await createCancellable(someAsyncFunction());
await createCancellable(anotherAsyncFunction());
}
将所有逻辑(对someAsyncFunction
和anotherAsyncFunction
的调用)包装到单个async
函数中,然后与错误竞争,这是很诱人的,但是没有什么能阻止新的错误发生时,包装器从继续执行到完成。因此,您对单个种族的处理方式很有意义。
发表评论:
这捕获了同步代码正确运行时排队的任何错误吗?
从下一个await
开始,它可能还不及您。让我们添加一些同步代码:
async function exampleFunction(emitter){
// Start synchronous block 0
const pError = new Promise((_, reject) => {
emitter.once('error', reject);
});
const createCancellable = promise => Promise.race([pError, promise]);
// End synchronous block 0
await createCancellable(someAsyncFunction());
// Start synchronous block 1
doThis(); // All of these are synchronous, starting
doThat(); // after `someAsyncFunction`'s promise resolves
doSomethingElse(); // and before we call `anotherAsyncFunction`
// End synchronous block 1
await createCancellable(anotherAsyncFunction());
// Start synchronous block 2
doYetAnotherThing(); // This is synchronous again, starting after
keepDoingStuff(); // `anotherAsyncFunction`'s promise resolves and
okayLastThingNow(); // continuing until the end of the function
// End synchronous block 2
}
两种情况:
在{em} someAyncFunction
的处理过程中,它正在等待其他完成的事件时,发生了eventemitter的错误。调用事件发射器的事件回调的作业将运行,拒绝pError
。这立即拒绝了Promise.race
并拒绝了exampelFunction
承诺; await createCancellable(someAsyncFunction());
行之后没有任何代码。
{em> someAsyncFunction
的承诺在运行“同步块1”时,发生了emem事件。在这种情况下,同步块将继续,因为无法中断同步作业以执行其他操作,因此来自事件发射器的回调被放入作业队列中。然后,当您执行await
时,当前作业结束并且可以运行其他作业。如果运行事件发射器的事件回调,它将拒绝该承诺,因此exampleFunction
从下一个await
开始被拒绝-但是,anotherAsyncFunction
可以被调用并开始,因为发生在调用Promise.race
之前。如果要避免触发anotherAsyncFunction
,则需要插入另一个await
,请参见***
注释:
async function exampleFunction(emitter){
// Start synchronous block 0
const pError = new Promise((_, reject) => {
emitter.once('error', reject);
});
const createCancellable = promise => Promise.race([pError, promise]);
// End synchronous block 0
await createCancellable(someAsyncFunction());
// Start synchronous block 1
doThis(); // All of these are synchronous, starting
doThat(); // after `someAsyncFunction`'s promise resolves
doSomethingElse(); // and before we call `anotherAsyncFunction`
// End synchronous block 1
await createCancellable(Promise.resolve()); // ***
await createCancellable(anotherAsyncFunction());
// Start synchronous block 2
doYetAnotherThing(); // This is synchronous again, starting after
keepDoingStuff(); // `anotherAsyncFunction`'s promise resolves and
okayLastThingNow(); // continuing until the end of the function
// End synchronous block 2
}
要更简单地处理#2,您可以传递createCancellable
回调以进行调用,如下所示:
async function exampleFunction(emitter){
// Start synchronous block 0
const pError = new Promise((_, reject) => {
emitter.once('error', reject);
});
const createCancellable = (callback, ...args) => {
return Promise.race([pError, Promise.resolve()])
.then(() => Promise.race([pError, callback(...args)]));
};
// End synchronous block 0
await createCancellable(someAsyncFunction); // *** no ()
// Start synchronous block 1
doThis(); // All of these are synchronous, starting
doThat(); // after `someAsyncFunction`'s promise resolves
doSomethingElse(); // and before we call `anotherAsyncFunction`
// End synchronous block 1
await createCancellable(anotherAsyncFunction); // *** no ()
// Start synchronous block 2
doYetAnotherThing(); // This is synchronous again, starting after
keepDoingStuff(); // `anotherAsyncFunction`'s promise resolves and
okayLastThingNow(); // continuing until the end of the function
// End synchronous block 2
}
请注意,我们不会调用 someAsyncFunction
或anotherAsyncFunction
,我们只是将函数传递给createCancellable
,并在首先检查事件发射器的拒绝后让它们调用
因此,这可能不只是简单地抛出await createCancellable(Promise.resolve());
就简单了。 :-)