map () с асин c против обещания. все () - PullRequest
1 голос
/ 23 апреля 2020

Если у меня есть массив элементов и я хочу выполнять параллельные операции с ними.

Я бы использовал promise.all().

Я знал, promise.all() принимает массив обещаний. Поправьте меня, если я ошибаюсь, я так не думаю.

Здесь , это ясно говорит.

Метод Promise.all () возвращает одиночное обещание, которое выполняется, когда все обещания, переданные как итеративные, были выполнены, или когда итерабельное не содержит обещаний или когда итеративное содержит обещания, которые были выполнены, и не обещания, которые были возвращены. Он отклоняется по причине первого обещания, которое отклоняет, или с ошибкой, обнаруженной первым аргументом, если этот аргумент обнаружил ошибку внутри него, используя блоки try / catch / throw.

Итак, да мы можем передать простые функции в promise.all(), и он разрешает, если они возвращаются, и отклоняет, если выдает ошибку.

Теперь посмотрите на приведенный ниже код.

const promises = todayAssignedJobs.map(async todayAssigned => {
  const [leaderboard, created] = await Leaderboard.findOrCreate({...});

  if (!created) {
    const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
    const commission = todayAssigned.commission + leaderboard.commission;
    const jobsCompleted = leaderboard.jobs_completed + 1;

    await Leaderboard.update({
      rating,
      commission,
      jobs_completed: jobsCompleted,
      updated_by: 'system',
    }, {
      where: {
        id: leaderboard.id,
      },
    });
  }

  await AssignedJob.update({
    is_leaderboard_generated: true,
  }, {
    where: {
      id: todayAssigned.id,
    },
  });
});

await Promise.all(promises);

Здесь у меня есть сомнения.

Мы выполняем итерацию для каждого элемента массива и асинхронно выполняем операции с ними. Они ничего не возвращают явно.

Итак, я думаю, что здесь карта выполняет параллельные операции.

Зачем тогда shuold использовать promise.all() здесь?

Ответы [ 3 ]

3 голосов
/ 23 апреля 2020

.map() не выполняет обещаний. Поэтому, когда вы передаете ему обратный вызов async, как вы, он не обращает никакого внимания на это возвращенное обещание. Таким образом, он просто запускает l oop один за другим, не ожидая ни одного из возвращающихся обещаний. Таким образом, все асинхронные операции, запущенные в .map() l oop, будут выполняться одновременно.

Если это то, что вы хотите, и вы хотите собрать все возвращенные обещания, чтобы вы могли позже Посмотрите, когда все они сделаны с Promise.all(), тогда этот шаблон хорошо работает:

Promise.all(someArray.map(callbackThatReturnsAPromiseHere))

И это обычный шаблон дизайна для него. На самом деле, библиотека обещаний Bluebird имеет специальную функцию, объединяющую эти две функции, которая называется Promise.map(). Он также предложил еще одну приятную функцию, которая позволяет вам контролировать, сколько одновременных асин c операций может выполняться одновременно (потому что это map() операция с учетом обещаний).

Похоже, вы пытаетесь понять если вы должны использовать только .map() и не использовать Promise.all(). Если вы сделаете это, вы будете выполнять свои асинхронные операции параллельно, но у вас не будет представления о том, когда они все будут выполнены, или о возможности собрать все результаты. Вы должны использовать Promise.all() в массиве возвращенных обещаний, чтобы знать, когда они все будут выполнены, и / или собирать их разрешенные результаты.

К вашему сведению, .map() ПРОСТО - просто l oop. Он не имеет никаких специальных асинхронных функций или каких-либо специальных функций параллельного запуска. Вы можете сделать то же самое с for l oop, если хотите. Он не приостанавливает ваш обратный вызов async, чтобы дождаться его выполнения, поэтому побочным эффектом его запуска является запуск нескольких параллельных асинхронных операций.

2 голосов
/ 23 апреля 2020

Вам нужно только Promise.all, если вы хотите что-то сделать, когда все операции завершены. Например:

const promises = todayAssignedJobs.map(async todayAssigned => {
  // lots of async stuff
});

await Promise.all(promises);

// now, all Promises have resolved
// alert the user that the leaderboard is completely updated

Если вам не нужно, чтобы что-либо происходило после того, как вы определили, что все Обещания выполнены, тогда нет смысла в Promise.all - вы также можете просто создать Обещания в oop и оставить их как есть. В этом случае, поскольку вы не будете использовать результирующий массив Promises, было бы более целесообразно использовать forEach (это метод массива, используемый для побочных эффектов).

Есть одна проблема хотя - вы не обрабатываете ошибки, но ошибки должны обрабатываться , иначе они будут выдавать предупреждения или выходить из процесса Node:

const processJob = async (todayAssigned) => {
  const [leaderboard, created] = await Leaderboard.findOrCreate({...});

  if (!created) {
    // ...

// ...
todayAssignedJobs.forEach(async todayAssigned => {
  try {
    await processJob(todayAssigned);
  } catch(e) {
    // handle errors
  }
});
1 голос
/ 23 апреля 2020

Цель Promise.all здесь - дождаться всех обещаний, прежде чем продолжить.

Если вы добавили console.log непосредственно перед await Promise.all(promises);, он будет работать синхронно до разрешения любых обещаний тогда как console.log сразу после этой строки появится только после all , обещания разрешены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...