LoginSignup
20
20

More than 5 years have passed since last update.

【Promise】再施行出来るPromise (Retmise)

Last updated at Posted at 2015-09-03

モジュール定義

以前に「非同期な自動再試行をネイティブのPromiseを用いて実装」で実装したときは用途が限られてしまったけど、こっちなら汎用的に使える。

retmise.js
(function (root) {

    'use strict';

    function Retmise(options) {
        if (this == null || this.constructor !== Retmise) {
            return new Retmise(options);
        }
        options         = options || {};
        options.retries = options.retries != null ? options.retries : 5;
        options.delay   = options.delay   != null ? options.delay   : 500;
        options.timeout = options.timeout != null ? options.timeout : 0;
        options.onRetry = typeof options.onRetry === 'function' ? options.onRetry : doNothing;
        this.options    = options;
    }

    Retmise.prototype.do = function (callback) {
        var _this = this;
        var count = 0;
        var rejected = false;
        return new Promise(function (resolve, reject) {
            (function self() {
                new Promise(callback).then(function (result) {
                    resolve(result);
                }, function (reason) {
                    if (count++ < _this.options.retries || _this.options.retries < 0) {
                        // 試行回数内なら再試行を予約
                        setTimeout(function () {
                            if (!rejected) {
                                // まだRejectされていなければ再試行
                                _this.options.onRetry(count);
                                self();
                            }
                        }, _this.options.delay);
                    } else {
                        reject(reason);
                    }
                });
            })();
            if (_this.options.timeout > 0) {
                setTimeout(function () {
                    // これ以上再試行しないようにフラグをセット
                    rejected = true;
                    reject('timeout');
                }, _this.options.timeout);
            }
        });
    };

    function doNothing() {}

    // CommonJSのrequire, Browserの通常読み込みに対応
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = Retmise;
    } else {
        root.Retmise = Retmise;
    }

})((this || 0).self || global); // Browser, Node.js, WebWorker に対応

new Retmise(options)

  • オブジェクトoptionsは以下の値を取ります。キーは全て省略可能であり、また引数自体も省略可能です。このオブジェクトはコピーされてRetmiseオブジェクト内部に保持されるので、後からの変更は適用されません。
キー デフォルト値 値の説明
retries 5 リトライ回数。0未満で無限試行。
delay 500 遅延させるミリ秒。0以下で即時再試行。
timeout 0 タイムアウトまでのミリ秒。0以下で無制限。
onRetry 空の関数 第1引数を初回を含むそれまでの試行回数とする関数。
リトライごとに実行される。
  • 引数自体を省略可能です。
  • ガード節があるのでnewを省略可能です。

Retmise.prototype.do(callback)

通常のPromiseのコンストラクタに相当する部分です。通常のPromiseを返します。自動的に再試行が行われる以外は全く同じです。

使用例

3000ミリ秒後にコンソールに出力される例
<!DOCTYPE html>
<title>Test</title>
<script src="retmise.js"></script>
<script>
    Retmise({retries: 5, delay: 1000}).do(function (resolve, reject) {
        var element = document.querySelector('div');
        element ? resolve(element) : reject('failed');
    }).then(function (element) {
        console.log(element); 
    }, function (reason) {
        console.error(reason);
    });
    setTimeout(function () {
        document.body.appendChild(document.createElement('div'));
    }, 3000);
</script>
20
20
1

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
20
20