2016-10-05 117 views
2

我有這樣的功能:進行下一步只有當功能已運行10次

function setIntervalX(callback, delay, repetitions): Promise<any> { 

    let promises = []; 

    var x = 0; 
    var intervalID = window.setInterval(function() { 
    callback(); 
    if (++x === repetitions) { 
     window.clearInterval(intervalID); 
     promises.push(new Promise((resolve, reject) => {}); 
    } 
    }, delay); 
    return Promise.all(promises); 
} 

我的目標是去調用測試功能和那些10個呼叫已經結束後,我想打電話給期待在我的功能。因此,這意味着我必須等待它結束了,像這樣:

setIntervalX(() => { 

    //logic here 

    }, 1000, 10).then(() => { 
        expect(something).toBe(anotherThing); 
        }); 

我覺得我這樣做的方式是醜陋的,而且可以做到bettery。有什麼建議麼?

+0

好的,我重新格式化了,你現在能幫忙嗎:)? –

+0

尊重,但看看上面。你真的會稱之爲「一貫且可讀」的格式嗎? 'callback'在第一個代碼塊中沒有對齊,這是誤導性的;第一個區塊在其他方面仍然具有不一致的縮進;而關於第二代碼塊的說法越少越好。明確你的帖子和代碼,並證明你花時間這樣做,提高了獲得良好答案的機會。 –

+0

如果這是一項測試,爲什麼您將它們隔開1秒的時間間隔,而不是將它們背靠背運行?從你的問題來看,「回調函數」是否可以返回一個承諾,也就是說,有效地表示一個異步操作,執行是否需要一秒以內(意味着測試依次執行)或更多(它們最終同時執行即並行)。澄清這可能會使問題變得更好。 – jib

回答

2

除非你需要個人的承諾(你永遠不會用到它們上面除了Promise.all),只使用一個單一的承諾:

function setIntervalX(callback, delay, repetitions): Promise<any> { 
    return new Promise(resolve => { 
     let x = 0; 
     let intervalID = window.setInterval(function() { 
      callback(); 
      if (++x === repetitions) { 
       window.clearInterval(intervalID); 
       resolve(); 
      } 
     }, delay); 
    }); 
} 
+0

不錯,但它還不夠優雅,可以做得更好? –

+0

@JerzyGruszka:除了在定時器功能中刪除不必要的'window.',我不知道你會做什麼。 –

+0

@ T.J.Crowder如果callback()拋出或返回被拒絕的承諾,則無法正確傳播錯誤。 – jib

1

您標記RxJS以及因此我會扔出來的Rx解決方案。

function setIntervalX(callback, delay, repetitions): Observable<any> { 
    //Emit an event every delay 
    return Rx.Observable.interval(delay) 
    //Only accept a certain number of events 
    .take(repetitions) 
    // Process the callback each time 
    .do(() => callback()) 
    // Convert the result into a promise 
    .toPromise(); 
} 

setIntervalX(() => { 
    //logic here 
}, 1000, 10) 
.then(() => {     
    expect(something).toBe(anotherThing); 
}); 
1

你希望有一個更優雅的解決方案,這個怎麼樣:

var wait = ms => new Promise(resolve => setTimeout(resolve, ms)); 
 

 
let setIntervalX = (cb, delay, reps) => 
 
    Promise.all(Array(reps).fill().map((n, i) => wait(delay * (i + 1)).then(cb))); 
 

 
// Demo: 
 

 
let test =() => Promise.resolve().then(() => (console.log("test"), "!")); 
 

 
setIntervalX(test, 1000, 10).then(results => console.log(results.join("")));

我解釋的代碼在你的問題是想支持的承諾,回國callback秒。這支持了這一點,並且也正確地傳播了錯誤,這與setInterval很難做到。

setIntervalsetTimeout API本身具有可怕的錯誤處理特性,並且最好用小的承諾函來返回函數,永遠不要再被直接調用。

請注意,對於高值repetitions,這不是特別有效。