ECMAScript7 async/await непоследовательное поведение в зависимости от того, используются ли скобки в функции стрелки или нет

Я столкнулся с непоследовательным поведением в Google Chrome 60.0.3112.78 (официальная сборка) (64-разрядная версия) при использовании современного ES6+ async/await, в зависимости от того, использую ли я квадратные скобки в функции стрелки, которая возвращает Обещание. То же самое происходит в Node.js. Мне трудно понять, почему.

Я понимаю, что это не то, как реализовать функцию sleep(), но это самый простой способ продемонстрировать. Рассмотрим следующий пример фрагмента кода.

function sleep(ms = 0) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

Как и ожидалось, это напишет a в консоль, подождет 5 секунд, а затем напишет b в консоль.


Более короткая запись с использованием функции стрелки для возврата Promise.

const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms)) }

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

Как и ожидалось, этот код ведет себя так же. a и b записываются в консоль с интервалом 5000 миллисекунд между ними.


Следующий код не работает. Единственное отличие состоит в том, что я не заключаю возврат Promise в скобки в первой строке.

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

В этом случае ожидание сна не работает. На самом деле этот код вообще ничего не делает. Он ничего не записывает в консоль, ни a, ни b.

Я считаю себя довольно опытным, но в настоящее время я не понимаю этого. Почему скобки важны в данном конкретном случае? Возвращаемое значение идентично, верно? И почему даже символ a не регистрируется в консоли?

Кто-нибудь, пожалуйста, объясните мне точно и конкретно, почему это так. Это баг или мне самому нужно поспать?

Большое тебе спасибо.


person Jochem Stoel    schedule 04.08.2017    source источник
comment
@4castle Если вы ссылаетесь на этот ответ, я рекомендую вместо этого использовать функцию declarations (function sleep(ms) { return … }) которым вообще не нужна точка с запятой :-)   -  person Bergi    schedule 05.08.2017


Ответы (1)


Значение имеет точка с запятой после функции стрелки. Написать

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
//                                                                 ^

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

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))(async () => { … })()

но функция sleep никогда не вызывается.

person Bergi    schedule 04.08.2017
comment
@Matthew Да, но если вы хотите опустить точки с запятой и позволить им автоматически вставляться везде, где это возможно, вы необходимо поместить один в начале каждой строки, начинающейся с (, [, /, +, - или `. - person Bergi; 05.08.2017
comment
Ха-ха, да, но неясность этой ошибки заставляет меня ценить дополнительное нажатие клавиши. - person Wolfie; 05.08.2017
comment
Спасибо! Вы правы, я не могу поверить, что пропустил это. Фу! Кстати, я на самом деле неукоснительно никогда не использую точку с запятой, если нет другого пути, и верю, что по этой привычке можно определить хороших разработчиков. Но я предвзят. Спасибо еще раз! :) - person Jochem Stoel; 05.08.2017
comment
Смысл в том, что проще всегда ставить точки с запятой, чем пытаться запомнить, когда они необходимы, а когда нет, и, таким образом, снижается вероятность внесения ошибки. - person Jaime; 05.08.2017
comment
@JochemStoel Я бы догадался, если бы вы также пропустили их в асинхронной функции :-) - person Bergi; 05.08.2017
comment
@ Хайме, я не согласен. Необходимость каждый раз помнить, нужно ли вам использовать точку с запятой или нет, помогает вам сосредоточиться как разработчику. Это принуждает вас к этому. Ничего на автопилоте. - person Jochem Stoel; 06.08.2017
comment
@JochemStoel Я предполагаю, что вы тратите по крайней мере один час, пытаясь понять, почему ваш код не работает должным образом. Автоматическая вставка точки с запятой (ASI) считается одной из наиболее спорных особенностей JavaScript. Мы должны относиться к ИСИ так, как будто его не существует. - person Jaime; 07.08.2017
comment
@Jaime Мы просто не должны забывать точки с запятой. Будь то в конце каждой строки или в начале каждой строки (которая начинается со скобки) не имеет значения. Это полностью личное предпочтение, и как только вы привыкнете к любому методу, вы сможете легко обнаруживать отсутствующие. Или пусть это сделает ваш линтер, для обоих стилей есть правила. - person Bergi; 07.08.2017
comment
@Bergi, не могли бы вы обновить свой ответ, включив в него код OP с точкой с запятой перед IIFE? - person Mihail Malostanidis; 03.03.2018
comment
@MihailMalostanidis Нет, разве недостаточно исправленной части? - person Bergi; 03.03.2018