Как вы запускаете setTimeout раз в секунду внутри цикла forEach? - PullRequest
2 голосов
/ 13 апреля 2019

Мой код для создания нескольких мест размещения в онлайн-сервисе с ограничением записи 60 в минуту:

  placementsToAdd.forEach((placement, index) => {
    setTimeout(() => {
      options.url = `https://api.company.com/placement?publisher_id=${existingPub ? existingPub : placementsJson[0].PublisherId}&site_id=${placement.siteId}`
      options.body = `{"placement":{"name":"${placement.placement}"}}`
      request(options, callback);  
    },1000 * (index + 1))
  })

Это работает следующим образом, но меня беспокоит время ожидания, если есть списокмест размещения 2000 или 3000 одновременно, время ожидания может быть чрезмерно большим.

Есть ли лучший способ реорганизовать этот код, чтобы мои запросы создавались по одному в секунду, несмотря ни на что?Без этого «* (index + 1)» кажется, что он продолжает пытаться построить все сразу, ударив об стену после 60.

Я пытался использовать обещания и асинхронное ожидание (что для меня ново)но, похоже, это не меняет поведение.

Спасибо!

По запросу, покажите, как я пытался использовать обещания с этим кодом:

  async function createThePlacements() {
    let promise = new Promise((resolve, reject) => {
      for (let i = 0; i < placementsToAdd.length; i++) {
        setTimeout(() => {
          options.url = `https://api.company.com/placement?publisher_id=${existingPub ? existingPub : placementsJson[0].PublisherId}&site_id=${placementsToAdd[i].siteId}`
          options.body = `{"placement":{"name":"${placementsToAdd[i].placement}"}}`
          request(options, callback);  
        },1000)
      }
    });

    let result = await promise; // pause till the promise resolves 
    console.log('result - ', result);
  }

  createThePlacements();

Итак, немного отказа от ответственности - как уже упоминалось, я никогда раньше не использовал Async Await, поэтомучитать, чтобы попытаться понять, как это работает.Кажется, это синтаксис, но в данный момент мой результат, похоже, ничего не значит, но код также продолжает делать то, что должен, просто пытаясь выполнить все вызовы в моем тесте 300 одновременно.

Кроме того, обратите внимание, у меня есть решимость внутри обратного вызова запроса вызова.Это решает проблему, так что даже следующие части моего приложения заканчиваются до самого конца.Вот почему у меня нет отклонения или разрешения здесь.

Ответы [ 2 ]

3 голосов
/ 13 апреля 2019

Как вы запускаете setTimeout раз в секунду внутри цикла forEach?

Самый простой подход:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

for (const placement of placementsToAdd) {
  const options = {...};
  request(options, callback);  
  await wait(1000);
}

await работает предсказуемовнутри простых циклов for, а не внутри forEach.

Я не коснулся вашего callback, но он должен обрабатывать ошибки.Возможен дополнительный рефакторинг.

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

1 голос
/ 13 апреля 2019

Лучшим вариантом будет иметь метод request, который возвращает Обещание.

Тогда вы можете переписать свой код следующим образом.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function requestPlacement(placement) {
  const options = {...};
  return request(options);
}

async function requestAllPlacements(placements) {
  for(let i = 0; i < placements.length; i+=60) {
    if (i > 0) {
      // wait 1 minute
      await(sleep(60000));
    }

    await Promise.all(
      placements
        .slice(i, 60)
        .map(requestPlacement);
    );
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...