能够中止asynchronous调用

我正在使用es7风格的asynchronous/等待方法babeljs。 我有一个主脚本将调用一个对所有返回承诺的对象数组的asynchronous方法。 我使用Promise.all()等待所有这些返回,但是,这些任务可能需要很长时间,如果他们超过了阈值,我想中止所有这些,并以合适的方式处理任务。

有没有办法完成这样的事情? 目前我能想到的唯一方法是产生一个调用这些方法并等待它们全部解决的过程,如果达到了时间限制,它可以终止进程并执行任何需要的处理。

更新:关于主脚本正在等待的这些方法的一些说明…他们可能正在做一连串的操作(调用外部系统,stream文件到某处等),而不是执行一个可以独立取消的单个操作。

更新#2:一些未经testing的半伪代码

class Foo1 { async doSomething() { // call some external system // copy some files // put those files somewhere else (s3) } } class Foo2 { async doSomething() { // Do some long computations // Update some systems } } class FooHandler { constructor() { this.fooList = []; } async start() { await Promise.all(this.fooList.map(async (foo) => { return await foo.doSomething(); })); } } let handler = new FooHandler(); handler.fooList.push(new Foo1()); handler.fooList.push(new Foo2()); // if this call takes too long because of slow connections, errors, whatever, // abort start(), handle it in whatever meaningful way, and continue on. await handler.start(); 

本地ES6承诺目前不支持直接取消。 在许多地方一直在谈论它,但它还没有在那里。

由于本地承诺不支持它,asynchronous/等待承诺的作品,目前没有内置的简单方法来中止它。 一种常见的方法是在创build返回承诺的操作时使用标记。

假设你已经promisified XHR GET:

 // simplification function ajax(url){ return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest; xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = reject; xhr.send(); }); } 

现在你想使用它:

 async function foo(){ let result = await ajax("/myApi"); let result2 = await ajax("/myApi2?token=" + result); } 

现在,假设我们想在某些情况下取消AJAX,我们可以传递一个令牌:

 function ajax(url, token = {}){ return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest; xhr.open("GET", url); Object(token).cancel = () => { xhr.abort(), reject(); }; xhr.onload = () => resolve(xhr.responseText); xhr.onerror = reject; xhr.send(); }); } 

这会让你做:

 async function foo(){ let token = {}; let req = ajax("/myApi", token); // note no await // now let's say we want to abort the request since we don't // need the data token.cancel(); // this will abort the token } 

这种方法需要与链接一起工作,幸运的是ES6语法,这不是一个大问题。 祝你好运,快乐的编码。

如果您可以迁移到Typescript(其中types是可选的,es6和一些es7function支持开箱即用)而不是Babel并使用Bluebird承诺,那么您可以实现您正在寻找的取消语义。

我创build了一个简单的模块,用默认的Typescript __awaiter helperreplace__awaiter一个支持Bluebird取消的帮助器: https : __awaiter

有了它,你可以使用与promise.cancel promise.cancel()promise.finally()相结合的同步/等待语法。

这真的取决于你需要使用的API。 目前大多数的asynchronousAPI节点的方法不容易“中断”( readfileasync等),除非你自己执行它们。

轻松取消预定的调度是不容易的。 到目前为止,API并没有考虑到这一点。 当API的低级实现不支持中止时,承诺也无能为力。

但是在某些API中,您可以截获进程的“步骤”,例如data事件stream和“下一个打勾”实现。 在那里你可以中止进一步的处理。 (Streams实际上是实现可拦截的IO东西的不错select)

经典的节点示例中,input“n”的斐波那契数列计算是根据请求提供的,逻辑是通过“下一个打勾”实现的。 在那里你可以在计算上设置一个超时时间,服务器会自动启动长时间运行的请求:

 var do_fibonacci_async = function(a,limiter,callback){ if(limiter.halt){ callback(limiter.msg); } else if(a <= 2){ callback(limiter.halt ? limiter.msg : 1); }else{ process.nextTick(function(){ do_fibonacci_async(a - 1,limiter, function(val1){ do_fibonacci_async(a - 2,limiter, function(val2){ callback(limiter.halt ? limiter.msg : val1+val2); }); }); }); } } exports.fibonacci_async = function(a,callback){ if(!a || isNaN(a)){ callback(new out("fibonacci", [], "")); return; } var limiter = {halt:false, msg:"Too large to compute"}; setTimeout(function(){ limiter.halt = true; },5000); do_fibonacci_async(a,limiter,function(val){ callback(new out("fibonacci", [a], val)); }); }