Как установить время ожидания на узле async await call

Как я могу добавить setTimeout к моему вызову функции async await?

у меня есть

    request = await getProduct(productids[i]);

где

const getProduct = async productid => {
        return requestPromise(url + productid);
   };

я пытался

    request = await setTimeout((getProduct(productids[i])), 5000);

и получил ошибку 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!
  }
};

Вот очень похожий вопрос: Как сделать таймаут кошмарного запроса.

jfriend00 30.04.2018 01:31

Вы имеете в виду, что запрос выполняется через 1 секунду или вы запускаете его немедленно, а если он не завершается в течение 1 секунды, вы его закрываете?

jfriend00 30.04.2018 01:32

К вашему сведению, библиотека запроса-обещания уже поддерживает параметр тайм-аута, поэтому, если вы просто хотите тайм-аут ожидания ответа, вы можете использовать параметр, уже встроенный в библиотеку просьба-обещание.

jfriend00 30.04.2018 01:35

@ jfriend00 спасибо за комментарии. Я действительно хочу поставить функцию ожидания, чтобы после одного запроса она ждала, прежде чем делать другой запрос. Раньше я не видел опции тайм-аута в библиотеке, спасибо за ссылку.

jenryb 30.04.2018 02:18

Этот параметр тайм-аута не является параметром ожидания для следующего запроса. Это совершенно разные вещи.

jfriend00 30.04.2018 02:21

@ jfriend00 Я понимаю это. Я добавил некоторые детали к вопросу, чтобы, надеюсь, прояснить, что мне не нужен тайм-аут для вызова API, а перерыв между вызовами

jenryb 30.04.2018 02:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
6
19 196
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

На самом деле у меня есть довольно стандартный фрагмент кода, который я использую для этого:

function PromiseTimeout(delayms) {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, delayms);
    });
}

Применение:

await PromiseTimeout(1000);

Если вы используете обещания Bluebird, они встроены как Promise.timeout.

Еще о вашей проблеме: вы проверили документацию по API? Некоторые API-интерфейсы сообщают вам, сколько вам нужно ждать до следующего запроса. Или разрешите загрузку больших объемов данных.

В Bluebird это Promise.delay вместо Promise.timeout.

Blade1336 27.07.2020 02:46
Ответ принят как подходящий

Вы можете использовать небольшую простую функцию, которая возвращает обещание, которое разрешается после задержки:

function delay(t, val) {
   return new Promise(function(resolve) {
       setTimeout(function() {
           resolve(val);
       }, t);
   });
}

И затем await внутри вашего цикла:

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

Примечание: я также переключил ваш цикл for на использование for/of, который не требуется, но он немного чище, чем у вас.

Спасибо! Это идеально, спасибо за включение примера использования. Также оцените изменение цикла for, не знал, что вы можете это сделать, поэтому я узнал дважды из этого ответа.

jenryb 30.04.2018 02:26

У меня есть один вопрос: знаете ли вы, ожидает ли асинхронный метод с использованием await завершения одного вызова API перед выполнением следующего? Если это так, то эта задержка необходима, если нет, мне может потребоваться найти способ делать вызовы серии, чтобы избежать жесткого кодирования в такой задержке.

jenryb 30.04.2018 02:35

@jenryb - Если getProduct(id) возвращает обещание, которое разрешается только после выполнения его асинхронной операции, тогда await getProduct(id) действительно будет ждать его завершения, а цикл for действительно будет ждать каждого вызова getProduct(id). Но (и это важно) ваша экспортированная функция getProducts() не ждет возврата. Он немедленно возвращается и возвращает обещание, которое разрешается, когда цикл for и все операции await выполнены.

jfriend00 30.04.2018 02:59

Начиная с узла v15 вы можете использовать API таймеров обещаний:

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

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

test();

Обратите внимание, что эта функция является экспериментальной и может измениться в будущих версиях.

Начиная с Node 15 и выше, есть новый API таймеров обещаний, который позволяет избежать создания упаковки:

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

console.info('before')
await setTimeout(1000)
console.info('after 1 sec')

Итак, ваши проблемы вы можете написать с помощью асинхронного итератора:

import {
  setTimeout
} from 'timers/promises'

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

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

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

getProducts()

Другие вопросы по теме