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

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
20
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

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

モジュール定義

以前に「非同期な自動再試行をネイティブの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>
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
20
Help us understand the problem. What are the problem?