【问题标题】:Proceed to next step only when function has been run 10 times仅当功能已运行 10 次后才能进行下一步
【发布时间】:2016-10-06 11:46:52
【问题描述】:

我有这个功能:

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 次调用结束后,我想在我的函数中调用 expect。所以这意味着我必须等待它结束,就像这样:

setIntervalX(() => {

     //logic here

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

我觉得我这样做的方式很丑陋,可以做得更好。有什么建议吗?

【问题讨论】:

  • 好的,我重新格式化了,你现在能帮忙吗:)?
  • 尊重,但请看上面。您真的会称其为“一致且可读”的格式吗? callback 在第一个代码块中未对齐,具有误导性;第一个块在其他方面仍然具有不一致的缩进;关于第二个代码块的说法越少越好。使您的帖子和代码清晰,并证明您花时间这样做,可以提高您获得好的答案的机会。
  • 如果这是一个测试,为什么要以 1 秒的间隔将它们分开,而不是让它们背靠背运行?从您的问题中也不清楚callback 是否可以返回一个承诺,即有效地表示一个异步操作,以及执行时间是否少于一秒(意味着测试按顺序执行),或者更多(它们最终同时执行即并行)。澄清这一点可能会成为一个更好的问题。
  • “通话已结束”是什么意思?如果您只是想在第 10 次通话被触发后恢复,那么setTimeout(something, 10000) 似乎就足够了。

标签: javascript typescript promise rxjs


【解决方案1】:

除非您需要单独的 Promise(除非在 Promise.all 中,否则您永远不会在上面使用它们),只需使用单个 Promise:

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);
    });
}

【讨论】:

  • 不错,但还是不够优雅,可以做得更好吗?
  • @JerzyGruszka:除了删除定时器功能上不必要的window.,我不确定你还能做什么。
  • @T.J.Crowder 如果 callback() 抛出或返回被拒绝的承诺,则无法正确传播错误。
  • @jib:我只是解决实际问题,而不是进行代码审查。
【解决方案2】:

你也标记了 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);
});

【讨论】:

    【解决方案3】:

    你想要一个更优雅的解决方案,怎么样:

    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("")));

    我将您问题中的代码解释为希望支持返回承诺的callbacks。这支持这一点,并且还可以正确传播错误,而 setInterval 很难做到这一点。

    setInterval 和 setTimeout API 本身具有糟糕的错误处理特性,最好紧紧地包裹在微小的承诺返回函数中,永远不要再被直接调用。

    请注意,对于 repetitions 的高值,这并不是特别有效。

    【讨论】:

      猜你喜欢
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 2020-03-14
      • 1970-01-01
      • 2017-07-29
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多