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)