Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
41
Help us understand the problem. What is going on with this article?
@sukobuto

ES2016 async/await キャンセル可能な非同期関数を実装する方法

More than 3 years have passed since last update.

stack overflow にいいやり方が載っていたので紹介します。
出典:Abort ecmascript7 async function

デモを書いてみました

まずはこちらを見てください。何がやりたいかがわかりやすくなっているかと思います。
jsfiddle で動きを見る:CancellationToken

async/await にはキャンセル処理を実装するための仕組みがありませんが、 async/await の元ネタである .NET framework に CancellationToken 構造体 というものがあります。

これを JS に持ち込むことで、キャンセル可能な async 関数を実装することができます。

CancellationToken クラス

CancellationToken(ES2016実装)
class CancellationToken {

  isCancellationRequested = false;

  constructor(parentToken = null) {
    this.cancellationPromise = new Promise(resolve => {
      this.cancel = e => {
        this.isCancellationRequested = true;
        if (e) {
          resolve(e);
        } else {
          var err = new Error("cancelled");
          err.cancelled = true;
          resolve(err);
        }
      }
    });
    if (parentToken && parentToken instanceof CancellationToken) {
      parentToken.register(this.cancel);
    }
  }

  register(callback) {
    this.cancellationPromise.then(callback);
  }

  createDependentToken() {
    return new CancellationToken(this);
  }

}

使い方

キャンセルできるようにしたい async 関数の引数に CancellationToken を受け取るようにします。

// キャンセル可能な非同期関数
function delayAsync(duration, cancellationToken = null) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, duration);
    if (cancellationToken) {
      cancellationToken.register(reject);
    }
  });
}

この関数に渡したトークンを使ってキャンセルすることができます。

// トークンを新しく作る
var ct = new CancellationToken();
// 1秒後にキャンセルされるようにする
delayAsync(1000)
    .then(ct.cancel);
// 2秒かかる処理をする
delayAsync(2000, ct)
    .then(() => console.log("ok"))
    .catch(e => console.log(e.cancelled ? "cancelled" : "some other err"));

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)
41
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
sukobuto
MVVM のおかげで生きてます。 WPF,Silverlight -> knockout.js -> Aurelia.js -> Xamarin knockout.js のドキュメント翻訳しました。→ http://kojs.sukobuto.com/

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
41
Help us understand the problem. What is going on with this article?