2017-02-24 13 views
2

私はクライアントから呼び出されるmyMainFunctionという関数を持っています。つまり、mypromisifiedという関数が呼び出されます。Javascript.Promise.rejectで再試行するか、または成功するまで

シナリオ: mypromisified機能が断続的に失敗することができ、私は達し試行のない成功するまで、または最大まで(指数関数的な増加で)遅延でこの関数を呼び出していないする必要があります。私が持っているもの

は、これまで

次のコードは、私のシナリオを示し、成功、まで繰り返されますが、特定のカウントが到達するまで、それは無期限ではなくしようと

// called once from the client 
 
myMainFuntion(); 
 

 
function rejectDelay(delay, reason) { 
 
    // call main function at a delayed interval until success 
 
    // but would want to call this only a limited no of times 
 
    setTimeout(() => { 
 
     myMainFuntion(); // calling main function again here but with a delay 
 
    }, delay); 
 
} 
 

 

 
function myMainFuntion() { 
 
    var delay = 100; 
 
    var tries = 3; 
 
    tryAsync().catch(rejectDelay.bind(null, delay)); 
 
} 
 

 
function tryAsync() { 
 
    return new Promise(function(resolve, reject) { 
 
    var rand = Math.random(); 
 
    console.log(rand); 
 
    if (rand < 0.8) { 
 
     reject(rand); 
 
    } else { 
 
     resolve(); 
 
    } 
 
    }); 
 

 
}

whileループ内部rejectDelayは、setInterval内の実際の関数が実行される前でもカウンタがインクリメントするため、確かに機能しません。このため、どうすればよいでしょうか?そう...

私はpromisifyingにそれが右のいずれかにそれを取得する方法を確認してください、それはカウンタをデクリメントdoesntのよう:(失敗しませんが、知っている、このようなsetIntervalな何かを試してみました。

function rejectDelay(delay, maximumTries, reason) { 
 
    return new Promise(function (resolve, reject) { 
 
    console.log(tries + ' remaining'); 
 
    if (--maximumTries > 0) { 
 
     setTimeout(function() { 
 
     foo(); 
 
     }, 500); 
 
    } 
 
    }); 
 
} 
 
function myMainFunction() { 
 
    var delay = 100; 
 
    var maximumTries = 3; 
 
    tryAsync().catch(rejectDelay.bind(null, delay, maximumTries)); 
 
}

+0

関連回答:(http://stackoverflow.com/questions/38213668/promise-retry-design-patterns/38214203#38214203)プロミスがデザインパターンを再試行]および[約束のステップを再試行]( http://stackoverflow.com/questions/37993365/retry-a-promise-step/37995874#37995874) – jfriend00

答えて

6
私は多くのことを使用してきたヘルパー関数のカップルを使用して

が、これは非常に容易になる

「ヘルパー」

Promise.wait = (time) => new Promise(resolve => setTimeout(resolve, time || 0)); 
Promise.retry = (cont, fn, delay) => fn().catch(err => cont > 0 ? Promise.wait(delay).then(() => Promise.retry(cont - 1, fn, delay)) : Promise.reject('failed')); 

コード:その関数内にネストされた関数を呼び出すために、 "非同期再帰" を使用するヘルパーの

function myMainFuntion() { 
     var delay = 100; 
     var tries = 3; 
     Promise.retry(tries, tryAsync, delay); 
} 

ES5バージョン

Promise.wait = function (time) { 
    return new Promise(function (resolve) { 
     return setTimeout(resolve, time || 0); 
    }); 
}; 
Promise.retry = function (cont, fn, delay) { 
    return fn().catch(function (err) { 
     return cont > 0 ? Promise.wait(delay).then(function() { 
      return Promise.retry(cont - 1, fn, delay); 
     }) : Promise.reject('failed'); 
    }); 
}; 
+0

簡潔な解決策に感謝します:)。私は '再試行'の再帰呼び出しを理解していますが、待機関数の周りに頭を浮かべることができません - >あなたは新しいPromiseを返すのですが、それを解決または拒絶することは明白ではありません。 - 私の頭の中で、 'promise.wait()'の '.then'は決して呼ばれませんでしたか?それをもう少し私に説明してもらえますか?あらかじめありがとうございます PS:私はhttps:// jsfiddleにここで作った裂け目から作業していることを知っています。私の頭の中で働いていない:( – Jaya

+1

'setTimeout'の最初の引数は実行する関数です...' resolve'に設定されています...したがってresolveは 'timeの後に呼び出されます'ms –

+0

ahh!gotcha!ありがとう! – Jaya

0

Aわずかに異なるアプローチ約束を返す:

function retry(func, maxTries, delay) { 
 
    var reTry = 0; 
 
    return new Promise(function(resolve, reject) { 
 
     function callFunc() { 
 
      try 
 
      { 
 
       func().then(resolve, function(reason) { 
 
        if(++reTry >= maxTries) { 
 
         reject(reason); 
 
        } 
 
        else { 
 
         setTimeout(callFunc, 
 
         typeof delay=="function" ? delay(retry) : delay); 
 
        } 
 
       }); 
 
      } 
 
      catch(e) { 
 
       reject(e); 
 
      } 
 
     } 
 
     callFunc();  
 
    }); 
 
} 
 

 
// ******* run snippet to test ******** 
 

 

 
var retryCount = 0; 
 
function getDelay(n) { 
 
// return 100 * n*n + 500; // for example 
 
     ++ retryCount; 
 
     return 100; // for testing 
 

 
} 
 

 
function testFunc() { 
 
    return Math.random() < 0.8 ? Promise.reject("too many tries") : Promise.resolve("success"); 
 
} 
 

 
retry(testFunc, 5, getDelay).then(
 
function(data) { console.log("data: %s, retryCount %s", data, retryCount);}, 
 
function(reason){console.log("reason: %s, retryCount %s", reason, retryCount);} 
 
)

関連する問題