Переходите к следующему шагу только тогда, когда функция была запущена 10 раз

#javascript #typescript #promise #rxjs

#javascript #typescript #обещание #rxjs

Вопрос:

У меня есть эта функция:

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

Моя цель — вызвать функцию в test, и после завершения этих 10 вызовов я хочу вызвать expect в своей функции. Это означает, что мне нужно дождаться ее завершения, например:

 setIntervalX(() => {

     //logic here

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

Я чувствую, что мой способ сделать это уродлив, и его можно сделать лучше. Есть предложения?

Комментарии:

1. хорошо, я переформатировал его, вы поможете сейчас :)?

2. С уважением, но посмотрите на вышесказанное. Вы бы действительно назвали это «последовательно и читабельно» отформатированным? callback смещен в первом блоке кода, что вводит в заблуждение; этот первый блок также по-прежнему имеет непоследовательные отступы другими способами; и чем меньше сказано о втором блоке кода, тем лучше. Прояснение вашего сообщения и кода и демонстрация того, что вы потратили на это время, повышает ваши шансы на получение хороших ответов.

3. Если это тест, почему вы размещаете их с интервалом в 1 секунду вместо того, чтобы просто запускать их последовательно? Из вашего вопроса также неясно callback , может ли возвращать обещание, т. Е. Фактически представляет асинхронную операцию, и требуется ли для выполнения меньше секунды (что означает, что тесты выполняются последовательно) или больше (они в конечном итоге выполняются одновременно, т. Е. Параллельно). Уточнение этого может сделать вопрос лучше.

4. Что вы подразумеваете под «завершением вызовов»? Если вы просто пытаетесь возобновить работу после завершения 10-го вызова, этого setTimeout(something, 10000) , по-видимому, достаточно.

Ответ №1:

Если вам не нужны отдельные обещания (вы никогда не используете их выше, кроме как в 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);
    });
}
  

Комментарии:

1. отлично, но это все еще не элегантно и может быть сделано лучше?

2. @JerzyGruszka: Кроме удаления ненужных window. функций таймера, я не уверен, что еще вы могли бы сделать.

3. @T.J.Crowder это не приводит к правильному распространению ошибок, если callback() выдает или возвращает отклоненное обещание.

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

Я интерпретирую код в вашем вопросе как желающий поддержать обещания, возвращающие callback s. Это поддерживает это, а также правильно распространяет ошибки, с которыми трудно справиться setInterval .

API setInterval и setTimeout сами по себе имеют ужасные характеристики обработки ошибок и лучше всего плотно упакованы в крошечные функции, возвращающие обещания, которые никогда не будут вызываться напрямую снова.

Обратите внимание, что для высоких значений repetitions это не особенно эффективно.