async await with setInterval


function first(){
console.log('first')
}
function second(){
console.log('second')
}
let interval = async ()=>{
await setInterval(first,2000)
await setInterval(second,2000)
}
interval();

想象一下,我在上面有这段代码。

当我运行它时,first()second()会同时被调用;first)()返回一些数据后如何调用second(),例如,如果first()完成,则只调用second()

因为我的代码first()将处理大量数据,如果这两个函数同时调用,那么服务器将很难。

每次first()返回一些数据时如何调用second()

如上所述setInterval如果你不阻止它,它就不能很好地与承诺相提并论。如果您清除间隔,则可以像以下方式使用它:

async function waitUntil(condition) {
return await new Promise(resolve => {
const interval = setInterval(() => {
if (condition) {
resolve('foo');
clearInterval(interval);
};
}, 1000);
});
}

以后你可以像这样使用它

const bar = waitUntil(someConditionHere)

您有几个问题:

  1. 承诺只能解决一次,setInterval()意味着多次调用回调,承诺不能很好地支持这种情况。
  2. 因此,无论是setInterval(),还是更合适的setTimeout()回报承诺,在这种情况下,await承诺都是没有意义的。

您正在寻找一个返回 Promise 的函数,该函数会在一段时间后解析(使用setTimeout(),可能不是setInterval()(。

幸运的是,创建这样的函数相当简单:

async function delay(ms) {
// return await for better async stack trace support in case of errors.
return await new Promise(resolve => setTimeout(resolve, ms));
}

使用此新的delay功能,您可以实现所需的流程:

function first(){
console.log('first')
}
function second(){
console.log('second')
}
let run = async ()=>{
await delay(2000);
first();
await delay(2000)
second();
}
run();
setInterval

不能很好地处理承诺,因为它会多次触发回调,而承诺会解析一次。

似乎setTimeout适合这种情况。它应该被承诺以便与async..await一起使用:

async () => {
await new Promise(resolve => setTimeout(() => resolve(first()), 2000));
await new Promise(resolve => setTimeout(() => resolve(second()), 2000));
}

await 表达式会导致异步暂停,直到 Promise 被解决

因此,您可以直接获得承诺的结果,而无需等待

对我来说,我想每 1 秒启动一次 Http 请求

let intervalid 
async function testFunction() {
intervalid = setInterval(() => {
// I use axios like: axios.get('/user?ID=12345').then
new Promise(function(resolve, reject){
resolve('something')
}).then(res => {
if (condition) {
// do something 
} else {
clearInterval(intervalid)
}    
})  
}, 1000)  
}
// you can use this function like
testFunction()
// or stop the setInterval in any place by 
clearInterval(intervalid)

你可以使用IFFE。这样,您可以避免myInterval不接受 Promise 作为返回类型的问题。

在某些情况下,您需要setInterval,因为您想调用一些未知次数的函数,中间有一些间隔。 当我遇到这个问题时,这对我来说是最直接的解决方案。我希望它能帮助某人:)

对我来说,用例是我想将日志发送到 CloudWatch,但尽量不要遇到每秒发送超过 5 个日志的限制异常。所以我需要保留我的日志,并在 1 秒的间隔内将它们作为批处理发送。我在这里发布的解决方案是我最终使用的解决方案。

async function myAsyncFunc(): Promise<string> {
return new Promise<string>((resolve) => {
resolve("hello world");
});
}
function myInterval(): void {
setInterval(() => {
void (async () => {
await myAsyncFunc();
})();
}, 5_000);
}
// then call like so
myInterval();

查看了所有答案,但仍然没有找到正确的答案,该答案可以完全按照 OP 的要求工作。这是我用于相同目的的:

async function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (await callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})()

在我的示例中,我还放置了间隔迭代计数和计时器本身,以防调用方需要对其进行处理。但是,没有必要

就我而言,我需要遍历图像列表,在每个图像之间暂停,然后在最后暂停更长的时间,然后再重新循环。 我通过结合上面的几种技术来实现这一点,递归调用我的函数并等待超时。 如果在任何时候另一个触发器改变了我的animationPaused:boolean,我的递归函数将退出。

const loopThroughImages = async() => {
for (let i=0; i<numberOfImages; i++){
if (animationPaused) {
return;
}
this.updateImage(i);
await timeout(700);
}
await timeout(1000);
loopThroughImages();
}
loopThroughImages();

Async/await 不要使承诺同步。 据我所知,这只是return Promise.then()的不同语法。 在这里,我重写了异步函数并保留了两个版本,因此您可以看到它的真正作用并进行比较。 它实际上是一连串的承诺。

// by the way no need for async there. the callback does not return a promise, so no need for await.
function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
// async function with async/await, this code ...
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})() //... returns a pending Promise and ...
console.log('i do not wait');
// ... is kinda identical to this code.
// still asynchronous but return Promise statements with then cascade.
(() => {
console.log('start again');
return waitInterval(first, 1000).then(() => {
return waitInterval(second, 1000).then(() => {
console.log('finish again');
});
});
})(); // returns a pending Promise...
console.log('i do not wait either');

您可以看到两个异步函数同时执行。 所以在这里使用间隔周围的承诺不是很有用,因为它仍然只是间隔,承诺不会改变任何东西,并且让事情变得混乱......

由于代码在间隔中反复调用回调,我认为这是一种更简洁的方法:

function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function executeThroughTime(...callbacks){
console.log('start');
let callbackIndex = 0; // to track current callback.
let timerIndex = 0; // index given to callbacks
let interval = setInterval(() =>{
if (callbacks[callbackIndex](timerIndex++)){ // callback return true when it finishes.
timerIndex = 0; // resets for next callback
if (++callbackIndex>=callbacks.length){ // if no next callback finish.
clearInterval(interval);
console.log('finish');
}
}
},1000)
}
executeThroughTime(first,second);
console.log('and i still do not wait ;)');

此外,此解决方案每秒执行一次回调。 如果回调是需要超过一秒才能解决的异步请求,并且我不能让它们重叠,那么,我将获得请求解析以调用下一个请求(如果我不想骚扰服务器,则通过计时器(。

这里的"递归"任务称为lTask,其功能与以前几乎相同,只是,由于我不再有间隔,因此每次迭代都需要一个新的计时器。

// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync1(i) {
console.log(`first pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that first big data'), Math.floor(Math.random()*1000)+ 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{
console.log(`first solved: ${i} ->`, result);
return i==2;
});
}
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync2(i) {
console.log(`second pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that second big data'), Math.floor(Math.random()*1000) + 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{ // promise is resolved
console.log(`second solved: ${i} ->`,result);
return i==4; // return a promise
});
}
function executeThroughTime(...asyncCallbacks){
console.log('start');
let callbackIndex = 0;
let timerIndex = 0;
let lPreviousTime = Date.now();
let lTask = () => { // timeout callback.
asyncCallbacks[callbackIndex](timerIndex++).then((result) => { // the setTimeout for the next task is set when the promise is solved.
console.log('result',result)
if (result) { // current callback is done.
timerIndex = 0;
if (++callbackIndex>=asyncCallbacks.length){//are all callbacks done ?
console.log('finish');
return;// its over
}
}
console.log('time elapsed since previous call',Date.now() - lPreviousTime);
lPreviousTime = Date.now();
//console.log('"wait" 1 sec (but not realy)');
setTimeout(lTask,1000);//redo task after 1 sec.
//console.log('i do not wait');
});
}
lTask();// no need to set a timer for first call.
}
executeThroughTime(simulateAsync1,simulateAsync2);
console.log('i do not wait');

下一步是用间隔清空 fifo,并用 Web 请求承诺填充它......

import {
setInterval,
} from 'timers/promises';
const interval = 100;
for await (const startTime of setInterval(interval, Date.now())) {
const now = Date.now();
console.log(now);
if ((now - startTime) > 1000)
break;
}
console.log(Date.now());

适用于 nodejs 的解决方案。

https://nodejs.org/api/timers.html#timerspromisessetintervaldelay-value-options

最新更新