it-swarm.com.ru

Вызов асинхронных / ожидающих функций параллельно

Насколько я понимаю, в ES7/ES2016 помещение нескольких await в коде будет работать аналогично связыванию .then() с обещаниями, что означает, что они будут выполняться одно за другим, а не в parallerl. Так, например, у нас есть этот код:

await someCall();
await anotherCall();

Правильно ли я понимаю, что anotherCall() будет вызываться только после завершения someCall()? Каков самый элегантный способ их параллельного вызова?

Я хочу использовать его в Node, так что, возможно, есть решение с асинхронной библиотекой?

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

273
Victor Marchuk

Вы можете ждать на Promise.all ():

await Promise.all([someCall(), anotherCall()]);
448
madox2

TL; DR

Используйте Promise.all для параллельных вызовов функций, поведение ответов не правильно при возникновении ошибки.


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

// Begin first call and store promise without waiting
const someResult = someCall();

// Begin second call and store promise without waiting
const anotherResult = anotherCall();

// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];

// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise

Пример JSbin: http://jsbin.com/xerifanima/edit?js,console

Caveat: Неважно, если вызовы awaitнаходятся в одной строке или в разных строках, если первый вызов awaitпроисходит после все асинхронных вызовов. Смотрите комментарий JohnnyHK.


pdate: этот ответ имеет другую временную привязку при обработке ошибок в соответствии с ответ @ bergi , он NOT выбрасывает ошибку как ошибка происходит, но после того, как все обещания выполнены. Я сравниваю результат с подсказкой @ jonny: [result1, result2] = Promise.all([async1(), async2()]), проверьте следующий фрагмент кода

const correctAsync500ms = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, 'correct500msResult');
  });
};

const correctAsync100ms = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 100, 'correct100msResult');
  });
};

const rejectAsync100ms = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, 'reject100msError');
  });
};

const asyncInArray = async (fun1, fun2) => {
  const label = 'test async functions in array';
  try {
    console.time(label);
    const p1 = fun1();
    const p2 = fun2();
    const result = [await p1, await p2];
    console.timeEnd(label);
  } catch (e) {
    console.error('error is', e);
    console.timeEnd(label);
  }
};

const asyncInPromiseAll = async (fun1, fun2) => {
  const label = 'test async functions with Promise.all';
  try {
    console.time(label);
    let [value1, value2] = await Promise.all([fun1(), fun2()]);
    console.timeEnd(label);
  } catch (e) {
    console.error('error is', e);
    console.timeEnd(label);
  }
};

(async () => {
  console.group('async functions without error');
  console.log('async functions without error: start')
  await asyncInArray(correctAsync500ms, correctAsync100ms);
  await asyncInPromiseAll(correctAsync500ms, correctAsync100ms);
  console.groupEnd();

  console.group('async functions with error');
  console.log('async functions with error: start')
  await asyncInArray(correctAsync500ms, rejectAsync100ms);
  await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms);
  console.groupEnd();
})();
88
Haven

Обновление:

Первоначальный ответ затрудняет (а в некоторых случаях невозможен) правильную обработку отклонений обещаний. Правильное решение - использовать Promise.all:

const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);

Оригинальный ответ:

Просто убедитесь, что вы вызываете обе функции, прежде чем вы ждете одну из них:

// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();

// Await both promises    
const someResult = await somePromise;
const anotherResult = await anotherPromise;
74
Jonathan Potter

Есть еще один способ без Promise.all () сделать это параллельно:

Во-первых, у нас есть 2 функции для печати чисел:

function printNumber1() {
   return new Promise((resolve,reject) => {
      setTimeout(() => {
      console.log("Number1 is done");
      resolve(10);
      },1000);
   });
}

function printNumber2() {
   return new Promise((resolve,reject) => {
      setTimeout(() => {
      console.log("Number2 is done");
      resolve(20);
      },500);
   });
}

Это последовательно:

async function oneByOne() {
   const number1 = await printNumber1();
   const number2 = await printNumber2();
} 
//Output: Number1 is done, Number2 is done

Это параллельно:

async function inParallel() {
   const promise1 = printNumber1();
   const promise2 = printNumber2();
   const number1 = await promise1;
   const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
9
user2883596

Я создал Gist тестирование нескольких разных способов выполнения обещаний с результатами. Может быть полезно увидеть варианты, которые работают.

6
SkarXa