LoginSignup
2
2

More than 3 years have passed since last update.

例外が発生したら一定時間待機してからリトライする

Last updated at Posted at 2020-02-15

JavaScriptではSleepに相当する処理が無いので気軽にリトライができない。async/awaitがあれば比較的簡単に解決できるが、IEにそのような機能は無い。

Promiseを使うことで解決できる。PromiseであればpolyfillがあるためIEでも利用できる。

ただ、いざ書いてみると大変面倒だったためメモしておく。

function retry(fn, opt){
    opt = opt || {};
    opt.times = opt.times || 3;
    opt.delay = opt.delay || function() { return 1000 }; // ExpornentialBackoff したいとき
    opt.abort = opt.abort || function() { return false }; // 中断したいときは true を返す
    opt.count = 0;
    opt.error = [];

    // 初回は即実行して欲しい
    var promise = new Promise(function(resolve,reject){
        var result;
        try{
            result = fn()
            resolve(result);
        }catch(e){
            opt.count++;
            opt.error.push(e);
            reject(opt);
        }
    });
    var i = 0;
    for(; i < opt.times; i++){
        promise = promise.catch(function(opt){
            // リトライは間隔を開けて欲しい
            return new Promise(function(resolve,reject){
                setTimeout(function(){
                    var result;
                    try {
                        if (opt.abort()) { return }
                        result = fn();
                        resolve(result);
                    }catch(e){
                        opt.count++;
                        opt.error.push(e);
                        reject(opt);
                    }
                }, opt.delay());
            });
        });
    }
    return promise;
}

以下の必ず例外を発生する関数を retry に投入すると、コンソールに1秒間隔で日付を6回(1+5回)表示し、最後に "fail" を表示する。

function fail() {
    console.log(new Date());
    throw 1;
}
retry(fail, { times: 5 }).catch(function(e){ console.log("fail") })

一方で、例外を発生しない場合は日付が1回表示されて終了する。

function pass() {
    console.log(new Date());
}
retry(pass, { times: 5 }).catch(function(e){ console.log("fail") })

更に、以下は途中で正常終了するため、コンソールには 1, 2, 3, pass が表示されて終了する。

var i = 0;
function safe() {
    i++;
    console.log(i);
    if (i < 3) { throw 1 }
}
retry(safe, { times: 5 }).then(function(){ console.log("pass") }).catch(function(e){ console.log("fail") })

以上

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2