2016-10-05 87 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,这不是特别有效。