#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
это не особенно эффективно.