モジュール定義
以前に「非同期な自動再試行をネイティブの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>