Promiseとリトライ
HTML
<div>
タスク成功率: <input type="number" id="successRate" max="100" min="0" value="5">%
</div>
<div>
リトライ回数: <input type="number" id="retryCount" max="100000" min="0" value="10">回
</div>
<div>
リトライ実装: <select id="retryImpl">
<option value="retryN">retryN</option>
<option value="retryExponentialBackoff">retryExponentialBackoff</option>
</select>
</div>
<div>
<button id="start">実行</button>
<button id="cancel" disabled="disabled">リトライキャンセル</button>
</div>
<div>
<textarea id="console" rows="20" cols="80" placeholder="ここに処理結果が出力されます" readonly></textarea>
</div>
JavaScript
const stopWatch = (() => {
let startTime = new Date().getTime();
return {
getTimeStamp() {
const current = new Date().getTime();
const time = current - startTime;
startTime = current;
return "+" + Math.floor(time / 1000) + "." + (("" + (time % 1000)).padStart(3, '0'));
},
clear() {
startTime = new Date().getTime()
}
}
})();
const clearLog = function() {
document.getElementById('console').innerHTML = "";
stopWatch.clear();
};
const printLog = function(...args) {
document.getElementById('console').innerHTML += `${stopWatch.getTimeStamp()}: ${args.join(' ')}\n`;
};
/**
* 1秒ぐらいかかってランダムで成功・失敗するタスク。
*/
function doTaskAsync(successRate) {
return new Promise((resolve, reject) => {
printLog("[Task]", "processing...")
setTimeout(() => {
if (Math.random() < successRate / 100.0) {
printLog("[Task]", "success")
resolve("SUCCESS");
} else {
printLog("[Task]", "failed")
reject("FAILED");
}
}, 1000);
})
}
/* ここから */
// キャンセルを通知するためのオブジェクトを作る
// AbortControllerを使ったほうがよさそう
window.AbortController = function(){
const signal = new EventTarget();
signal.aborted = false;
return {
signal,
abort(){
signal.aborted = true;
signal.dispatchEvent(new Event('abort'));
}
}
};
/**
* 指定されたミリ秒だけPromiseの完了を待つ。
* AbortSignalが渡されていたら、Signalの状態によってはキャンセル(reject)する。
*/
function sleepAsync(milliseconds, signal) {
return new Promise((resolve, reject) => {
const timer = setTimeout(resolve, milliseconds);
if (signal) {
const onabort = () => {
clearTimeout(timer);
reject();
};
if(signal.aborted){
// イベント後に呼ばれると下のコールバックでは拾えないので、そのケースを考慮している
onabort();
}else{
signal.addEventListener('abort', onabort);
}
}
});
}
/**
* リトライ実装のベース
*/
function retry(func, retryDelay, determinationRetry, signal) {
const isFunction = (obj) =>...