如何在异步等待调用节点上设置timeout

jen*_*ryb 3 callback settimeout node.js async-await

如何在async await函数调用中添加setTimeout?

我有

    request = await getProduct(productids[i]);
Run Code Online (Sandbox Code Playgroud)

哪里

const getProduct = async productid => {
        return requestPromise(url + productid);
   };
Run Code Online (Sandbox Code Playgroud)

我试过了

    request = await setTimeout((getProduct(productids[i])), 5000);
Run Code Online (Sandbox Code Playgroud)

并得到了TypeError: "callback" argument must be a function有意义的错误.请求在一个循环内部,这使我在api调用上达到了速率限制.

exports.getProducts = async (req, res) => {
  let request;
  for (let i = 0; i <= productids.length - 1; i++) {
    request = await getProduct(productids[i]);
    //I want to wait 5 seconds before making another call in this loop!
  }
};
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 12

您可以使用一个简单的小函数来返回延迟后解析的promise:

function delay(t, val) {
   return new Promise(function(resolve) {
       setTimeout(function() {
           resolve(val);
       }, t);
   });
}
Run Code Online (Sandbox Code Playgroud)

然后await,在你的循环中:

exports.getProducts = async (req, res) => {
  let request;
  for (let id of productids) {
    request = await getProduct(id);
    await delay(5000);
  }
};
Run Code Online (Sandbox Code Playgroud)

注意:我也将你的for循环切换到for/of不需要的循环使用,但比你的更清洁.

  • @jenryb - 如果 `getProduct(id)` 返回一个只有在异步操作完成时才解决的承诺,那么 `await getProduct(id)` 确实会等待它完成,而 `for` 循环确实会等待每个调用“getProduct(id)”。但是(这很重要),导出的函数“getProducts()”不会等待返回。它立即返回并返回一个 Promise,当“for”循环和所有“await”操作完成时,该 Promise 就会被解析。 (2认同)

Lei*_*ifb 12

从节点 v15 开始,您可以使用Timers Promises API

const timersPromises = require('timers/promises');

async function test() {
  await timersPromises.setTimeout(1000);
}

test();
Run Code Online (Sandbox Code Playgroud)

请注意,此功能是实验性的,可能会在未来版本中发生变化。


Giu*_*ini 10

实际上,我有一段非常标准的代码用于执行此操作:

function PromiseTimeout(delayms) {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, delayms);
    });
}
Run Code Online (Sandbox Code Playgroud)

用法:

await PromiseTimeout(1000);
Run Code Online (Sandbox Code Playgroud)

如果您使用 Bluebird 承诺,那么它内置为Promise.timeout.

更多关于您的问题:您是否检查过 API 文档?一些 API 会告诉您在下一个请求之前必须等待多少时间。或者允许大批量下载数据。


Man*_*lon 5

从 Node 15 及更高版本开始,有新的Timers Promises API可以让您避免构建包装:

import {
  setTimeout,
  setImmediate,
  setInterval,
} from 'timers/promises';

console.log('before')
await setTimeout(1000)
console.log('after 1 sec')
Run Code Online (Sandbox Code Playgroud)

因此,您可以使用异步迭代器来编写您的问题:

import {
  setTimeout
} from 'timers/promises'

async function getProducts (req, res) {
  const productids = [1, 2, 3]

  for await (const product of processData(productids)) {
    console.log(product)
  }
}

async function * processData (productids) {
  while (productids.length > 0) {
    const id = productids.pop()
    const product = { id }
    yield product
    await setTimeout(5000)
  }
}

getProducts()

Run Code Online (Sandbox Code Playgroud)