NodeJS 使用setInterval异步等待

lb3vh1jj  于 2023-02-03  发布在  Node.js
关注(0)|答案(8)|浏览(269)
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()

ktecyv1j

ktecyv1j1#

如上所述,setInterval不适用于承诺 *,如果您不停止它 *。如果您清除间隔,您可以使用它:

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

以后您可以像这样使用它

const bar = waitUntil(someConditionHere)
83qze16e

83qze16e2#

你有几个问题:
1.承诺只能解析一次,setInterval()意味着多次调用回调,承诺不支持这种情况。
1.无论是setInterval()还是更合适的setTimeout()都不会返回Promises,因此,await在此上下文中对它们执行操作是毫无意义的。
您正在寻找一个函数,该函数返回一个Promise,该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();
bejyjqdl

bejyjqdl3#

setInterval不能很好地处理promise,因为它多次触发回调,而promise解析一次。
看起来setTimeout符合这个情况,为了和async..await一起使用,应该对其进行承诺:

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

relj7zay4#

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)
toe95027

toe950275#

可以使用IFFE,这样就可以避免myInterval不接受Promise作为返回类型的问题。
有些情况下你需要setInterval,因为你想调用某个函数未知的次数,其间有一定的间隔。当我面对这个问题时,这对我来说是最直接的解决方案。我希望它能帮助到一些人:)
对我来说,我想把日志发送到CloudWatch,但是尽量不要遇到Throttle异常,因为每秒发送的日志超过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();
uklbhaso

uklbhaso6#

看了所有的答案,但仍然没有找到一个正确的工作,正是如何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');
})()

在我的示例中,我还放置了interval迭代计数和计时器本身,以防调用者需要对它做些什么。

lkaoscv7

lkaoscv77#

在我的例子中,我需要迭代一个图像列表,在每个图像之间暂停,然后在结束时暂停更长时间,然后重新循环。我通过结合上面的几种技术来实现这一点,递归调用我的函数并等待超时。如果在任何时候另一个触发器更改了我的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();
kt06eoxx

kt06eoxx8#

Async/await不会使promises同步。据我所知,这只是return Promise.then()的语法不同。这里我重写了async函数,并保留了两个版本,这样你就可以看到它真正做了什么并进行比较。事实上,这是一个Promises的级联。

// 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');

你可以看到这两个异步函数同时执行,所以在这里使用promise和interval并不是很有用,因为它仍然只是interval,promise没有改变任何东西,而且会让事情变得混乱...
由于代码在一个区间内反复调用回调函数,我认为这是一种更简洁的方法:

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与间隔,并填补它与网络请求承诺...

相关问题