2016-09-24 42 views
1

如何將此算法編碼爲JavaScript中的承諾?Javascript:承諾等待條件或嘗試次數後中止

// condition: some situation that is not true 
// interval: period to wait before trying again 
// retriesAllowed: maximum number of retries to make before aborting 
// retriesMade: number of retries made so far 
while() { 
    if (condition) return true; // indicates success 
    if (retriesMade < retriesAllowed) return false; // or throw an exception 
    ++retriesMade; 
    wait(interval); 
} 

這是不行的,因爲它實際上並沒有在移動之前等待檢查,以解決爲true或false:

var check =() => { 
    if (condition) return true; // indicates success 
    if (retriesMade < retriesAllowed) return false; // or throw an exception 
    ++retriesMade; 
    setTimeout(check,interval) 
} 
check(); 
+0

[https://github.com/kriskowal/q](https://github.com/kriskowal/q) –

+1

@CodeSpirit [本地承諾](https://developer.mozilla.org/ EN-US /文檔/網絡/的JavaScript /參考/ Global_Objects /無極)。 –

+0

到目前爲止你能弄清楚什麼?你能分享你嘗試過的一個片段嗎? (Stack Overflow不是一個代碼編寫服務,這裏有一個期望,你首先已經投入了一些你自己的努力。) –

回答

2

這是不行的,因爲它實際上並沒有等待檢查移動之前解析爲真或假。那

一部分可能是故障/退出條件似乎是反轉,所以它會在第一輪檢查condition後可能永遠退出:

// retriesMade starts at 0, which is likely already less-than retriesAllowed 
if (retriesMade < retriesAllowed) return false; 

// probably should be 
if (retriesMade >= retriesAllowed) return false; 

除此之外, ,缺乏等待是通過異步操作設計的,例如setTimeout()等待給定的延遲間隔。周圍的代碼將始終繼續執行,無需等待結果。

而不是期望他們等待,你需要建立一個方法,當過程已經實際完成並通過該信息進行通知。承諾是一個選擇。

旁註:行爲和其他選項的詳盡的解釋在「How do I return the response from an asynchronous call?

與他們提供的,取代使用returnthrow的,他們提供resolve()reject()函數信號成功或失敗時分別被調用。他們的.then().catch()方法可用於設置延續。

var tries = new Promise((resolve, reject) => { 
    var retriesMade = 0; 
    var interval = 1000; 

    var check =() => { 
     if (condition) { resolve(); } 
     if (retriesMade >= retriesAllowed) { reject(); } 
     ++retriesMade; 
     setTimeout(check, interval); 
    }); 

    check(); 
}); 

tries.then(
    () => console.log('success'), 
    () => console.log('failure') 
); 

同樣,更徹底地使用承諾,含有一個函數(untilLimited)迭代以及允許條件(exitUpon)是異步的,如果需要的話的替代版本。

function delay(milliseconds) { 
    return new Promise(function (resolve) { 
    setTimeout(resolve, milliseconds); 
    }); 
} 

function untilLimited(limit, waitTime, exitUpon) { 
    return Promise.resolve() 
    .then(exitUpon) 
    .then(result => { 
     if (result) return true; 
     if (!(--limit > 0)) return Promise.reject('Limit exceeded.'); 
     return delay(waitTime) 
     .then(() => untilLimited(limit, waitTime, exitUpon)) 
    }); 
} 

untilLimited(5, 500,() => false /* condition */) 
    .then(
    (result) => console.log('success', result), 
    (result) => console.log('failure', result) 
); 
+0

你不應該在你的回調代碼中包裝一個'新的Promise',你應該實際使用* promises – Bergi

+0

@Bergi你能詳細說明你的意思嗎?我不知道一個原生的,基於Promise的'setTimeout()'等價物,所以看起來有些包裝是不可避免的。儘管如此,它可能會被最小化。 –

+0

是的,但是你應該只包裝* setTimeout',而不是其他任何東西,然後使用承諾的算法。 – Bergi

0

您可以使用q庫(或$q在angular)返回一個延遲對象,並在後臺運行該時間間隔,如果經過幾次嘗試,condition不滿足,則拒絕承諾。

Example for Angular

+0

這不是一個好的答案。 Angular在這裏甚至沒有相關 –

+0

您可以使用q庫而不使用角度。 $ q只是一個角度的包裝。核心庫工作原理相同 – eavidan