Вот

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

const value1 = await getValue1Async();
const value2 = await getValue2Async();
// use both values

Мне нужно сделать что-то подобное?

const p1 = getValue1Async();
const p2 = getValue2Async();
const value1 = await p1;
const value2 = await p2;
// use both values
 Benjamin Gruenbaum23 окт. 2017 г., 20:43
Близко к дублированию этого вопроса некоторое время назад - но я предпочитаю сохранить это, поскольку A) async / await сейчас встречается гораздо чаще, чем генераторы, и B) это довольно просто сформулировано.
 Ben23 окт. 2017 г., 14:29
Спасибо. Дополнительный вопрос: будет ли следующая сила ждать обоих (и отбрасывать результаты)await p1 && await p2?
 Florian23 окт. 2017 г., 14:32
Интересный вопрос, является ли p1 Promise <boolean>, который разрешается в false. Это будет короткое замыкание?
 T.J. Crowder23 окт. 2017 г., 17:29
@Florian: Да, это будет (короткое замыкание), что не очень хорошая вещь. :-) Бен: Нет, он не будет (обязательно подождет обоих; как указывает Флориан, если первое разрешит ложное значение, он не будетПодождите для второго вообще, и поэтому вы можете получить необработанную ошибку отклонения [если p2 отклоняет]). Вы также получите один, если оба обещания отклоняются. Я обновил свой ответ, чтобы решить эту проблему ...
 Florian23 окт. 2017 г., 14:28
Нижний блок кода будет делать то, что вам нужно. В качестве альтернативы используйте решение Кая.

Ответы на вопрос(4)

Используйте .catch () и Promise.all ()

что вы правильно обрабатываете отклонения, и вы можете безопасно использовать Promises.all (), не сталкиваясь с необработанными отклонениями. (Изменить: разъяснение за обсуждение: не ошибкаunhandled rejection но просто отклонения, которые не обрабатываются кодом.Promise.all() бросит первое обещание отказа и будетигнорировать остальное).

В приведенном ниже примере возвращается массив [[error, results], ...], чтобы упростить обработку результатов и / или ошибок.

let myTimeout = (ms, is_ok) =>
  new Promise((resolve, reject) => 
    setTimeout(_=> is_ok ? 
                   resolve(`ok in ${ms}`) :
                   reject(`error in ${ms}`),
               ms));

let handleRejection = promise => promise
  .then((...r) => [null, ...r])
  .catch(e => [e]); 

(async _=> {
  let res = await Promise.all([
    myTimeout(100, true),
    myTimeout(200, false),
    myTimeout(300, true),
    myTimeout(400, false)
  ].map(handleRejection));
  console.log(res);
})();

Вы можете бросить из catch (), чтобы остановить ожидание всех (и отменить результаты остальных), однако - вы можете делать это только один раз за блоки try / catch, поэтому необходимо поддерживать и проверять флаг has_thorwn, чтобы убедиться, что никаких необработанных ошибок не происходит.

let myTimeout = (ms, is_ok) =>
  new Promise((resolve, reject) =>
    setTimeout(_=> is_ok ?
                   resolve(`ok in ${ms}`) :
                   reject(`error in ${ms}`),
               ms));

let has_thrown = false;

let handleRejection = promise => promise
  .then((...r) => [null, ...r])
  .catch(e => {
    if (has_thrown) {
      console.log('not throwing', e);
    } else {
      has_thrown = 1;
      throw e;
    }
  });

(async _=> {
  try {
    let res = await Promise.all([
      myTimeout(100, true),
      myTimeout(200, false),
      myTimeout(300, true),
      myTimeout(400, false)
    ].map(handleRejection));
    console.log(res);
  } catch(e) {
    console.log(e);
  }
  console.log('we are done');
})();

 niry17 нояб. 2018 г., 19:49
Зачем кому-то -1 без объяснения причин?
 niry17 нояб. 2018 г., 20:26
@ Берджи, об ответе на вопрос: Promise.all () не отвечает? Кроме того, «... и предоставлена ​​возможность работать одновременно» - без правильной обработки, если одно отклонено, другим не предоставляется возможность вернуть результат.
 Bergi17 нояб. 2018 г., 20:10
Я думаю, что это на самом деле не отвечает на вопрос, иcatch в этом месте действительно нет необходимости избегать необработанных отказов. И что[error, results] шаблон действительно плохая идея
 Bergi17 нояб. 2018 г., 20:53
Нет не нужно.catch() на индивидуальные обещания,Promise.all полностью способен предотвратить необоснованные отклонения от них (как обсуждено в принятом ответе) самостоятельно.
 niry17 нояб. 2018 г., 20:18
@Bergi - без правильной обработки отклонений нет способа избежать такого необработанного отклонения обещания (которое подробно обсуждается в принятом ответе), которое (в будущем) завершит процесс узла. Шаблон [err, results] является лишь примером того, как передать и обработать несколько ошибок в конце.

 const [value1, value2] = await Promise.all([getValue1Async(),getValue2Async()]);

Более подробный пример приведен ниже, если он помогает понять:

const promise1 = async() => {
  return 3;
}

const promise2 = async() => {
  return 42;
}

const promise3 = async() => {
  return 500;
  // emulate an error
  // throw "something went wrong...";
}

const f1 = async() => {

  try {
    // returns an array of values
    const results = await Promise.all([promise1(), promise2(), promise3()]);
    console.log(results);
    console.log(results[0]);
    console.log(results[1]);
    console.log(results[2]);

    // assigns values to individual variables through 'array destructuring'
    const [value1, value2, value3] = await Promise.all([promise1(), promise2(), promise3()]);

    console.log(value1);
    console.log(value2);
    console.log(value3);

  } catch (err) {
    console.log("there was an error: " + err);
  }

}

f1();

 Ben23 окт. 2017 г., 14:28
Будет ли моя попытка в конце моего вопроса работать?
 Kai23 окт. 2017 г., 14:40
Я понял твою идею. ИМХО, это должно работать :). Извините за мое неосторожное подтверждение
Решает вместо обещаний

 new Promise( resolve => setTimeout(resolve, ms, data) )
const reject = (ms, data) => new Promise( (r, reject) => setTimeout(reject, ms, data) )
const e = e => 'err:' + e
const l = l => (console.log(l), l)

;(async function parallel() {

  let task1 = reject(500, 'parallelTask1').catch(e).then(l)
  let task2 = wait(2500, 'parallelTask2').catch(e).then(l)
  let task3 = reject(1500, 'parallelTask3').catch(e).then(l)

  console.log('WAITING')

  ;[task1, task2, task3] = [await task1, await task2,  await task3]

  console.log('FINISHED', task1, task2, task3)

})()

Как указывалось в других ответах, отклоненное обещание может привести к необработанному исключению.
Вот этот.catch(e => e) это хитрый маленький трюк, который ловит ошибку и передает ее по цепочке, позволяя обещаниюresolve, вместоrejecting.

Если вы найдете этот код ES6 некрасиво, посмотрите дружелюбнееВот.

Решение Вопроса
TL; DR

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

const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);

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

Подробности:

Ваше решение запускает их параллельно, но всегда ждет завершения первого, а затем ожидания второго.Если вы просто хотите запустить их, запустить их параллельно и получить оба результата, это нормально. (Нет, продолжайте читать ...) Обратите внимание, что если на выполнение первой (скажем) пяти секунд уходит, а во-вторых, происходит сбой в течение одной секунды, ваш код будет ждать полные пять секунд, а затем произойдет сбой.

К сожалению, в настоящее время нетawait синтаксис для параллельного ожидания, так что у вас есть неловкость, которую вы перечислили, илиPromise.all, (Там жебыло обсуждениеawait.all или похожие, хотя; возможно когда-нибудь.)

Promise.all версия:

const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);

... что более кратко, и также не ожидает завершения первой операции, если вторая не удалась быстро (например, в моем примере пять секунд / одна секунда выше, вышеприведенное будет отклонено через одну секунду, а не ждать пять) , Также обратите внимание, что в исходном коде, если второе обещание отклоняется до того, как первое обещание разрешается, вы вполне можете получить ошибку «необработанное отклонение» в консоли (в настоящее время вы используете Chrome v61), хотя эта ошибка может быть ложной (поскольку выделать, в конце концов, справиться с отказом). Но еслиобе отклонения обещаний, вы получите подлинную необработанную ошибку отклонения, потому что поток контроля никогда не достигаетconst value2 = await p2; и, таким образом, отклонение p2 никогда не обрабатывается.

Необработанные отклонения - это плохая вещь ™ (настолько, что скоро NodeJS прервет процесс на действительно необработанных отклонениях, точно так же, как необработанные исключения - потому что это то, чем они являются), поэтому лучше избегать «получите обещание»await это "образец в вашем вопросе.

Вот пример разницы во времени в случае сбоя (при использовании 500 мс и 100 мс, а не 5 секунд и 1 секунда), и, возможно, также, возможно, ложная необработанная ошибка отклонения (откройтереальный консоль браузера, чтобы увидеть это):

const getValue1Async = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, "value1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error");
  });
};

// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
  try {
    console.time("separate");
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    const value1 = await p1;
    const value2 = await p2;
  } catch (e) {
    console.error(e);
  }
  console.timeEnd("separate");
})();

// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
  try {
    console.time("Promise.all");
    const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
  } catch (e) {
    console.timeEnd("Promise.all", e);
  }
}, 1000);
Open the real browser console to see the unhandled rejection error.

И здесь мы отвергаем обаp1 а такжеp2, что приводит к не поддельной необработанной ошибке отклонения наp2:

const getValue1Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 500, "error1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error2");
  });
};

// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
  try {
    console.time("separate");
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    const value1 = await p1;
    const value2 = await p2;
  } catch (e) {
    console.error(e);
  }
  console.timeEnd("separate");
})();

// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
  try {
    console.time("Promise.all");
    const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
  } catch (e) {
    console.timeEnd("Promise.all", e);
  }
}, 1000);
Open the real browser console to see the unhandled rejection error.

В комментарии вы спросили:

Дополнительный вопрос: будет ли следующая сила ждать обоих (и отбрасывать результаты)await p1 && await p2?

При отклонении обещания возникают те же проблемы, что и в исходном коде:p1 разрешается, даже еслиp2 отклоняет ранее; это может привести к ошибочной необоснованной ошибке отклонения, еслиp2 отвергает раньшеp1 решает; и он генерирует подлинную необработанную ошибку отклонения, если обаp1 а такжеp2 отклонить (потому чтоp2Отклонение никогда не обрабатывается).

Вот тот случай, когдаp1 решает иp2 отвергает:

const getValue1Async = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, false);
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error");
  });
};

(async () => {
  try {
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    console.log("waiting");
    await p1 && await p2;
  } catch (e) {
    console.error(e);
  }
  console.log("done waiting");
})();
Look in the real console (for the unhandled rejection error).

... и где оба отвергают:

const getValue1Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 500, "error1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error2");
  });
};

(async () => {
  try {
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    console.log("waiting");
    await p1 && await p2;
  } catch (e) {
    console.error(e);
  }
  console.log("done waiting");
})();
Look in the real console (for the unhandled rejection error).

 Benjamin Gruenbaum24 окт. 2017 г., 11:53
То есть никто не делает "GC based"все же (Firefox сделал в какой-то момент, не уверен, что они все еще делают) - PR BridgeAR показывает подход, который мы рассматриваем прямо сейчас. Зоны также могут быть интересной идеей.
 T.J. Crowder23 окт. 2017 г., 14:37
@Ben: между тобой иPromise.all что я только что отредактировал, чтобы вызвать, к вашему сведению.
 Benjamin Gruenbaum24 окт. 2017 г., 09:34
Вawait p1 && await p2 если и p1, и p2 отклоняют, тогда p2 - необработанное отклонение (и обнаружение на основе GC все равно законно убьет процесс). Я говорил только о случае отказа p2, в то время как p1 все еще ожидает рассмотрения.
 Benjamin Gruenbaum24 окт. 2017 г., 11:52
@ T.J.Crowder «наш код» в данном случае это проект Node. В частности, это та часть кода, в которой я участвовал - извините за двусмысленность. Вот как мы это делаем:github.com/nodejs/node/blob/master/lib/internal/process/... - Естьgithub.com/nodejs/node/pull/15126 а такжеgithub.com/nodejs/node/pull/15335 о текущей работе. В Chrome вы можете увидеть привязки V8 наgithub.com/nwjs/chromium.src/blob/... который запускается в ProcessQueue после задачи.
 Benjamin Gruenbaum23 окт. 2017 г., 20:41
«(настолько, что скоро NodeJS прервет процесс при необработанных отклонениях, как необработанные исключения - потому что это то, что они есть)» - формулировка предупреждения об устаревании вызывает сожаление, и я сожалею об этом - но мы будемникогда убить узел по коду выше - мы будем: A) делать необработанные отклонения на основе GC B) предупреждать оочень долго в ожидании операции, которые GC пропустил, вероятно, C) только когда-либо убивают Node.js, если мы можем доказать, что отклонение не обработано (первый случай). Я понимаю, что ситуация запутанная, и я прошу прощения за это - мы сделаем лучше.

Ваш ответ на вопрос