Оказывает ли ожидание невыполнения обещания какой-либо заметный эффект?

#javascript #ecmascript-2017

#javascript #ecmascript-2017

Вопрос:

Можно await не обещать, и это так хорошо.

Все эти выражения допустимы и не вызывают ошибок:

 await 5
await 'A'
await {}
await null
await undefined 
  

Есть ли какой-либо обнаруживаемый эффект ожидания невыполнения обещания? Есть ли какая-либо разница в поведении, о которой следует знать, чтобы избежать потенциальной ошибки? Есть ли различия в производительности?

Следующие две строки полностью совпадают или они теоретически отличаются?:

 var x = 5
var x = await 5
  

Каким образом? Есть какой-нибудь пример, демонстрирующий разницу?

PS: По словам авторов TypeScript, разница есть:

var x = await 5; это не то же самое, что var x = 5; ; var x = await 5; назначит x 5 в следующем tern, где as var x = 5; будет вычисляться немедленно.

Ответ №1:

await это не сбой. Если ожидаемая вещь не является обещанием, она завернута в обещание, и это обещание ожидается. Поэтому await изменяется порядок выполнения (но, тем не менее, вы не должны полагаться на это):

Следующие выходные данные 1, 2, 3:

 console.log(1);

(async function() {
  var x = await 5;
  console.log(3);
})();

console.log(2);  

При await удалении это 1, 3, 2:

     console.log(1);

    (async function() {
      console.log(3);
    })();

    console.log(2);  

Кроме того, await работает не только на instanceof Promise s, но и на каждом объекте с .then методом:

 await { then(cb) { /* nowhere */ } };
console.log("will never happen");
  

Есть ли какой-либо заметный эффект от ожидания невыполнения обещания?

Конечно, .then вызывается, если оно существует для ожидаемой вещи.

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

Не называйте метод «then», если вы не хотите, чтобы это было обещание.

Есть ли различия в производительности?

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

Комментарии:

1. «но, тем не менее, вам не следует полагаться на это» Почему бы и нет?

2. @aBetterOliver пример: вы запускаете два очень коротких действия и хотите поработать с их результатом. Вы знаете, что действие 1 завершается раньше, чем действие 2, поэтому вы сохраняете результат 1 в переменной и получаете к нему доступ, когда выполняется 2. Теперь кто-то когда-нибудь изменяет алгоритм, так что 1 работает медленнее, чем 2. Ваш код ломается, и никто не знает почему. Если вам нужно выполнять асинхронные задачи в определенном порядке, вы должны записать это явно.

3. @JonasWilms Ваш пример не относится к вашему заявлению. Вы заявили, что не следует полагаться на тот факт, что await изменяет порядок выполнения. Это неправильно, мы полагаемся на это все время (т. Е. при использовании атомарности синхронных блоков). В вашем примере речь идет о двух асинхронных задачах, одна из которых зависит от эмпирического (но не гарантированного) времени выполнения другой, что является лишь общим наблюдением за параллельным программированием: вы не можете полагаться на порядок несопоставимых транзакций в графе приоритетов

4. Я не согласен с тем, что первый пример соответствует (простите за каламбур) примеру OP. Для этого вам придется дождаться журнала консоли, await console.log(3); и в этом случае не будет заметной разницы в поведении .

Ответ №2:

Полностью согласен с заявлениями Джонаса. Одна вещь, на которую не было ответа в его вопросе, заключалась в том, являются ли следующие две строки полностью одинаковыми или они теоретически отличаются?:

следующие две строки не совсем одинаковы, они теоретически отличаются.

  1. var x = 5
  2. var x = await 5

время выполнения в моей консоли для 1-го и 2-го операторов составляет 0,008056640625 мс и 0,055908203125 мс соответственно. async / await, setTimeout и т.д. — это API, предоставляемые временем выполнения, в котором выполняется время выполнения JavaScript. Установка await для невыполнения обещания будет выполнена в event-loop . Строка 1 будет выполнена сразу после достижения stack , но строка 2 займет несколько времени (миллисекунд), поскольку сначала она перейдет к stack , а затем к task queue после пропуска раздела ожидания WebAPI, потому что обещание не подлежит разрешению, и, наконец, после этого управление будет stack снова передано для выполнения.

Комментарии:

1. Я думаю, что на этот вопрос уже был дан ответ с помощью фрагмента кода примера. В любом случае спасибо!

2. на самом деле последняя часть вопроса отсутствовала, хотя т. е. Следующие две строки полностью совпадают или они теоретически отличаются? .

3. Пример кода от @JonasWilms очень четко показал разницу…

4. отлично. тогда предположим, что это другое объяснение 🙂

5. Это важное различие, потому что такое поведение было «исправлением» ошибки для нас, реализованной младшим инженером, который не осознавал, что функция, которую они await создавали, не была обещанием и, следовательно, не должна была ничего делать. «Но это исправляет ошибку!» (ошибка в условиях гонки, которая была «решена» путем помещения необещанной функции в цикл событий … после других событий), сказали они. Мы и не подозревали, что никто из нас не знал об этом поведении await ….

Ответ №3:

Ожидаемый код оборачивается обещанием, если ожидаемая вещь не имеет then свойства. Следовательно, хотя есть разница в производительности (это занимает больше времени), в поведении нет заметной разницы, если только то, что вы ожидаете, не имеет then свойства — в этом случае поведение может быть непредсказуемым, если ожидаемая вещь на самом деле не является обещанием, которое будет выполнено.