取消javascript中的异步调用链

取消javascript中的异步调用链,javascript,ecmascript-6,Javascript,Ecmascript 6,我正在研究在javascript中取消异步等待链的问题,我发现作者指出,为了取消这样的链: call1; call2; call3; 您需要像这样包装它们: 试一试{ 等待承诺[ 电话1, 取消 ]; } 犯错误{ if err instanceof CancelationError返回; } 试一试{ 等待承诺[ 电话2, 取消 ]; } 犯错误{ if err instanceof CancelationError返回; } 试一试{ 等待承诺[ 呼叫3, 取消 ]; } 犯错误{ if e

我正在研究在javascript中取消异步等待链的问题,我发现作者指出,为了取消这样的链:

call1; call2; call3; 您需要像这样包装它们:

试一试{ 等待承诺[ 电话1, 取消 ]; } 犯错误{ if err instanceof CancelationError返回; } 试一试{ 等待承诺[ 电话2, 取消 ]; } 犯错误{ if err instanceof CancelationError返回; } 试一试{ 等待承诺[ 呼叫3, 取消 ]; } 犯错误{ if err instanceof CancelationError返回; } 这是什么样的原因呢?一旦你进入了等待期,你就再也无法走出等待期,除非你的承诺被解决或拒绝

我被告知,您可以使用生成器取消整个链,而无需包装每个呼叫


有人能解释一下如何在不包装每个异步调用的情况下包装整个链吗?

这不是最好的解决方案,但您可以在承诺中轮询取消变量:

const delay=t=>new Promiseresolve=>setTimeoutresolve,t//测试目的 const call1=>new promisersolve=> {setTimeout=>{console.logcall1已完成;resolvecall1},1000} const call2=>new promisersolve=> {setTimeout=>{console.logcall2已完成;resolvecall2},1000} const call3=>new promisersolve=> {setTimeout=>{console.logcall3已完成;resolvecall3},1000} 让取消=假; 常数isCancelled==>{ 返回新的PromiseSolve,拒绝=>{ 常数a=setInterval=> { ifcancelled{rejectcancelled;clearIntervala} },50 } } 异步函数过程{ 试试{ 等待承诺。比赛[呼叫1,取消] 等待承诺。比赛[呼叫2,取消] 等待承诺。比赛[呼叫3,取消] } catch{console.loge} } 异步函数运行{ console.logtest案例1: 过程 setTimeout=>cancelled=true,500//测试用例1-仅运行call1 等待延迟3000;取消=错误 console.logtest案例2: 过程 setTimeout=>cancelled=true,1500//测试用例2-运行call1和call2 等待延迟3000;取消=错误 console.logtest案例3: 过程 setTimeout=>cancelled=true,3000//测试用例3-运行调用 }
运行为什么需要取消异步/等待链?也许这个概念会更好? 你觉得这个主意怎么样? /**在下列情况之一中抛出新错误 *调用将停止执行并转到 *挡块 */ 试一试{ 等待电话1; 等待电话2; 等待电话3; }抓住e{ console.error.message;
} 不需要生成器,异步包装函数可以实现以下功能:

函数CancelableAsyncChain…函数{ 让取消=假; 异步函数调用函数{ 函数的let f{ 如果取消{ break;//如果你想让承诺得到解决 抛出new CancellationError;//如果希望拒绝承诺 } 等待f; } } 常量取消=>{ 取消=真; } const promise=callFunctions; 取消,取消; 回报承诺; } //用法 异步函数f1{} 异步函数f2{} 异步函数f3{} 设CancelablePromise=CancelableAsyncChainF1、f2、f3; setTimeout=>CancelablePromise.cancel,1000; 可撤销的承诺,那么 =>console.logSuccess, =>console.logError或已取消 ;
是的,您可以将其包装在一个生成承诺的生成器中,然后针对每个承诺进行取消竞争:

async function run(cancel, fn) {
  const gen = fn();
  let result = gen.next();
  let next;
  while (!result.done) {
    try {
      next = await Promise.race([cancel, result.value]);
    } catch (err) {
      if (err instanceof CancelationError)
        result = gen.return();
      else
        result = gen.throw(err);
      continue;
    }
    result = gen.next(next);
  }
}

run(isCanceled(), function*() {
  yield call1();
  yield call2();
  yield call3();
});

需要一个生成器来创建暂停播放生成器函数和一个运行器

发电机:

常量生成器=函数*可取消,…promise{ 对于let i=0;i{ 设置超时=>{ 取消; }, 2000; }; } 让计数=0; 函数调用{ 返回新的PromiseSolve,拒绝=>{ 设置超时=>{ 解析计数++; }, 500; };
}你是说等待电话;等待电话2;等待呼叫3?在您的情况下,如果呼叫1被取消,则不会调用呼叫2?@NilankaManoj正确且不会调用3either@dagda1我编辑了我的答案并设置了三个测试用例。我发现了一个很好的例子,原因很多。一个可能是分块上传一个文件,而您想要取消整个上传。代码中没有取消。在每次调用中抛出承诺拒绝,以取消整个链。我知道您可以使用try-catch和async-await。那不是我想要的
我在问我怎么取消第二次呼叫而第三次呼叫却没有被呼叫?你是说,你有一个大文件,你需要拆分并发送文件部分,如果其中一部分失败,你想取消所有调用?你是说setTimeout而不是setInterval?这仍然需要包装我在问题setInterval中得到的每个调用,是否已取消,继续查找取消。@dagda1您所说的需要包装是什么意思?在我的解决方案中,直接调用1、2、3调用。请看Bergi的答案。
const generator = function* (cancelable, ...promies) {
  for (let i = 0; i < promies.length; i++) {
    yield Promise.race([promies[i](), cancelable]);
  }
};
async function runner(caller) {
  let finished = false;

  do {
    let { done, value } = caller.next();
    try {
      const data = await value;
      console.log(data);
      finished = done;
    } catch (error) {
      finished = true;
      console.log(error);
    }
  } while (!finished);
}