2015-10-19 40 views
9

「超時間隔」的良好模式我正在編寫一些代碼,每N毫秒輪詢一個資源,這應該在M秒後超時。我希望整個事情都是儘可能使用藍鳥的承諾。到目前爲止,我提出的解決方案使用節點間隔,可取消藍鳥許諾和藍鳥超時功能。使用Promises

我想知道是否有更好的方法來做藍鳥和一般的承諾超時間隔?主要是通過確保間隔停止在這一點,永遠不會無限期地繼續下去。

var Promise = require('bluebird'); 

function poll() { 
    var interval; 

    return new Promise(function(resolve, reject) { 
    // This interval never resolves. Actual implementation could resolve. 
    interval = setInterval(function() { 
     console.log('Polling...') 
    }, 1000).unref(); 
    }) 
    .cancellable() 
    .catch(function(e) { 
     console.log('poll error:', e.name); 
     clearInterval(interval); 
     // Bubble up error 
     throw e; 
    }); 
} 

function pollOrTimeout() { 
    return poll() 
    .then(function() { 
     return Promise.resolve('finished'); 
    }) 
    .timeout(5000) 
    .catch(Promise.TimeoutError, function(e) { 
     return Promise.resolve('timed out'); 
    }) 
    .catch(function(e) { 
     console.log('Got some other error'); 
     throw e; 
    }); 
} 

return pollOrTimeout() 
    .then(function(result) { 
    console.log('Result:', result); 
    }); 

輸出:

Polling... 
Polling... 
Polling... 
Polling... 
poll error: TimeoutError 
Result: timed out 

回答

5

我會做這樣的事情 -

function poll() { 
    return Promise.resolve().then(function() { 
    console.log('Polling...'); 
    if (conditionA) { 
     return Promise.resolve(); 
    } else if (conditionB) { 
     return Promise.reject("poll error"); 
    } else { 
     return Promise.delay(1000).then(poll); 
    } 
    }) 
    .cancellable() 
} 

另外要注意的Promise constructor anti-pattern

+1

不錯。你將如何完成這個時間間隔?看起來像是拋出錯誤的唯一出路。我知道Promise構造函數是一種反模式,但在這種情況下它似乎很適合(與事件+ Promises相同,但這是另一個主題)。 – Chris911

+0

好吧,現在我明白你的問題。檢查我的編輯。 – vinayr

+0

是的,這是有效的。謝謝並接受答案。 – Chris911

1

劉若英Wooller做一個很好的點:

警告:不幸的是,遞歸在這樣的JavaScript將最終達到飽和調用堆棧,並導致內存不足異常

即使不例外,這是浪費的空間,以及異常的風險可能會延長投票延期。

我認爲這是重要的,足以喜歡的setInterval:

var myPromise = new Promise((resolve, reject) => { 
    var id = window.setInterval(() => { 
     try { 
      if (conditionA) { 
       window.clearInterval(id); 
       resolve("conditionA"); 
      } else if (conditionB) { 
       throw new Error("conditionB!"); 
      } 
     } catch(e) { 
      window.clearInterval(id); 
      reject(e); 
     } 
    }, 1000); 
}); 

有跡象表明,滿足這一要求,其中我喜歡promise-waitfor最好的幾個NPM包。它長38行,完成這項工作。

var myPromise = waitFor(() => { 
    if(conditionA) return true; 
    if(conditionB) throw new Error("conditionB!"); 
    return false; 
}); 
+0

如果(conditionA)是一個承諾,你能向我解釋如何實現這一點嗎?我永遠無法逃避承諾鏈,在waitFor()中返回一個簡單的'true'或'false'。 – NZHammer

+1

隨時爲'conditionA'是一個承諾添加一個單獨的問題。可能解決方案涉及'Promise.race'。 –

+0

我讀過如果你的投票比你的setinverval運行時間更長,它會建立隊列。然後當它完成時,它必須處理隊列。並且最好使用setTimeout和遞歸來啓動另一個setTimeout。 – TamusJRoyce