Несколько ожидающих в одной строке (вложенные вызовы asyn c) - PullRequest
2 голосов
/ 04 февраля 2020

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

async function resolveAfterNSeconds(n, value) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(value);
    }, n*1000);
  });
};

async function test(which) {
  const start = new Date().getTime();
  let result;
  switch (which) {
    case 1:
      result = await resolveAfterNSeconds(10, await resolveAfterNSeconds(2, 'done'));
      break;
    case 2:
      result = await resolveAfterNSeconds(2, await resolveAfterNSeconds(10, 'done'));
      break;
    case 3:
      result = await resolveAfterNSeconds(10, resolveAfterNSeconds(2, 'done'));
      break;
    case 4:
      result = await resolveAfterNSeconds(2, resolveAfterNSeconds(10, 'done'));
      break;
    case 5:
      result = resolveAfterNSeconds(10, await resolveAfterNSeconds(2, 'done'));
      break;
    case 6:
      result = resolveAfterNSeconds(2, await resolveAfterNSeconds(10, 'done'));
      break;
  }
  const end = new Date().getTime();
  console.log([which, result, (new Date().getTime()-start)/1000]);
}

test(1); // [1, 'done', 12], as expected
test(2); // [2, 'done', 12], as expected
test(3); // [3, 'done', 10], as expected (kind of)
test(4); // [4, 'done', 10], but expected: [4, Promise, 2]
test(5); // [5, Promise, 2], as expected
test(6); // [6, Promise, 10], as expected

Я думаю, что я понимаю, почему в случае 3 вместо Promise возвращается 'done' - тайм-аут 2с к тому времени уже истек (я прав ?).

Однако я не понимаю, случай 4: Кажется, что await в начале также каким-то образом относится к внутреннему Promise, потому что в противном случае это Promise не должно быть возвращается (вместо 'done') через 2 с?

Но если внешний await на самом деле относится и к внутреннему Promise, не значит ли это, что случаи 1 и 2 не являются смысл и всегда следует заменять на случаи 3 и 4 (соответственно), чтобы два или более await в одной строке никогда не были полезны?

Ответы [ 2 ]

1 голос
/ 04 февраля 2020

Мне кажется, я понимаю, почему в случае 3 вместо соответствующего обещания возвращается «готово» - тайм-аут 2с к тому времени уже закончился (я прав?).

Нет, это то же самое, что и случай 4.

Однако я не понимаю, случай 4: кажется, что ожидание в начале также как-то связано с внутренним Обещанием, потому что в противном случае не должно t Это обещание будет возвращено (вместо «выполнено») через 2 с?

Если вы разрешите обещание (X) с другим обещанием (Y), тогда обещание X принимает состояние обещание Y.

Но если внешнее ожидание фактически относится и к внутреннему Обещанию, не означает ли это, что случаи 1 и 2 не имеют смысла и должны всегда заменяться случаями 3 и 4 (соотв.),

Нет. Они имеют различное поведение.

Если вы await обещание (Y) и используете его разрешенное значение в качестве аргумента функции, которая создает другое обещание (X), то эта функция не запустится, пока Y не выполнит resolved.

Если вы не ждете его, он запустится до разрешения Y (поэтому две операции, заключенные в обещания, могут выполняться параллельно).

0 голосов
/ 04 февраля 2020

По сути, async/await - это просто оболочка над Promise. Если вы вызываете любую функцию async, она возвращает Promise, и вызов ее с помощью await останавливает выполнение основного контекста и ожидает завершения Promise. Но если вы вызовете его без await, тогда это будет простой вызов функции, Promise начнет выполнение, но ничто не будет ждать его завершения, а остальная часть вашего кода будет выполняться синхронно.

Так, в вашем примере в случае 4 вызов resolveAfterNSeconds с await создает обещание около resolveAfterNSeconds(2, value), а вызов resolveAfterNSeconds(10, value) в параметрах без await выполняет resolveAfterNSeconds(10, value) синхронно, что приводит к передаче внутреннего Promise в качестве второго параметра.

Следовательно, await resolveAfterNSeconds(2, value) останавливает выполнение основного контекста, и внутри него создается цепочка Promise, поэтому выполнение будет продолжаться только тогда, когда будет разрешена вся цепочка Promise, и результат цепочки Promise равен done - последнее разрешенное значение, которое приходит к переменной result.

Вот почему вы получаете значение done;

...