4

ES7 非同期関数をキャンセルする方法はありますか?

この例では、クリックすると、新しい関数を呼び出す前に非同期関数呼び出しを中止したいと考えています。

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();
});
4

2 に答える 2

6

JavaScript にはまだ何も組み込まれていませんが、独自のものを簡単に作成できます。

MS.Net は、タスクのキャンセルにキャンセル トークンの概念を使用します (.net では Promises に相当します)。これは非常にうまく機能するので、ここに 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)
于 2015-10-01T22:28:16.867 に答える