终止ecmascript7 async函数

Abort ecmascript7 async function

本文关键字:函数 async ecmascript7 终止      更新时间:2023-09-26

是否有办法取消ES7异步功能?

在这个例子中,在单击时,我想在调用new之前中止异步函数调用。

async function draw(){
  for(;;){
    drawRandomRectOnCanvas();
    await sleep(100);
  }
}
function sleep(t){
  return new Promise(cb=>setTimeout(cb,t));
}
let asyncCall;
window.addEventListener('click', function(){
  if(asyncCall)
    asyncCall.abort(); // this dont works
  clearCanvas();
  asyncCall = draw();
});

JavaScript还没有内置任何东西,但是您可以轻松地自己编写。

。Net使用取消令牌的概念来取消任务(相当于。Net中的承诺)。它工作得很好,所以这里有一个JavaScript的精简版本。

假设您创建了一个用于表示取消的类:

function CancellationToken(parentToken){
  if(!(this instanceof CancellationToken)){
    return new CancellationToken(parentToken)
  }
  this.isCancellationRequested = false;
  var cancellationPromise = new Promise(resolve => {
    this.cancel = e => {
      this.isCancellationReqested = true;
      if(e){
        resolve(e);
      }
      else
      {
        var err = new Error("cancelled");
        err.cancelled = true;
        resolve(err);
      }
    };
  });
  this.register = (callback) => {
    cancellationPromise.then(callback);
  }
  this.createDependentToken = () => new CancellationToken(this);
  if(parentToken && parentToken instanceof CancellationToken){
    parentToken.register(this.cancel);
  }
}

,然后你更新你的睡眠功能,以了解这个令牌:

function delayAsync(timeMs, cancellationToken){
  return new Promise((resolve, reject) => {
    setTimeout(resolve, timeMs);
    if(cancellationToken)
    {
      cancellationToken.register(reject);
    }
  });
}

现在您可以使用令牌来取消传递给它的异步函数:

var ct = new CancellationToken();
delayAsync(1000)
    .then(ct.cancel);
delayAsync(2000, ct)
    .then(() => console.log("ok"))
    .catch(e => console.log(e.cancelled ? "cancelled" : "some other err"));
http://codepen.io/spender/pen/vNxEBZ

…或者使用async/await样式来做或多或少相同的事情:

async function Go(cancellationToken)
{
  try{
    await delayAsync(2000, cancellationToken)
    console.log("ok")
  }catch(e){
    console.log(e.cancelled ? "cancelled" : "some other err")
  }
}
var ct = new CancellationToken();
delayAsync(1000).then(ct.cancel);
Go(ct)

除非你的问题纯粹是理论性的,否则我假设你正在使用Babel, Typescript或其他一些转译器来支持es6-7,并且可能在遗留环境中使用一些polyfill来实现承诺。虽然很难说将来什么会成为标准,但有一种非标准的方式可以得到你今天想要的东西:

  1. 使用Typescript获取es6的特性和async/await。
  2. 在所有环境中使用Bluebird的承诺,以获得良好的承诺取消支持。
  3. 使用cancelable-awaiter,这使得蓝鸟取消在Typescript中与async/await很好地配合。