Неподнятые переменные (let, const), используемые в немедленно вызываемой асинхронной функции перед объявлением указанных переменных

Должен ли работать следующий код?

(async () => {
  await new Promise(r => setTimeout(r, 1000))
  useNum();
})();

let num = 10;
function useNum() {
  return num + 1;
}

https://jsbin.com/tayotitepa/edit?html,output

Safari на iOS (v13.3) говорит, что это невозможно (переменная num не существует), тогда как Chrome и Firefox считают, что это нормально.

Если вы удалите строку await new Promise..., Chrome и Firefox будут жаловаться.

Кажется, что Chrome и Firefox здесь правы, потому что мы не await используем сразу же вызванную асинхронную функцию, и поэтому к тому времени, когда строка await new Promise... будет завершена, остальная часть скрипта уже будет обработана. Но я решил проверить, потому что, возможно, спецификация говорит, что речь идет строго о порядке объявления переменных и использовании этих переменных, и поэтому не имеет значения "время" использование переменных.


person joe    schedule 15.02.2020    source источник
comment
Я не думаю, что проблема имеет какое-либо отношение к async/await. Сафари просто неправильно.   -  person Pointy    schedule 15.02.2020
comment
Кроме того, let и const подняты; просто он работает иначе, чем var подъем.   -  person Pointy    schedule 15.02.2020
comment
Отлично работает в Safari High Sierra.   -  person CertainPerformance    schedule 15.02.2020


Ответы (1)


Я пробовал это с разными сценариями. Я заметил, что

  1. async/await не имеет к этому никакого отношения.
  2. let num поднимается, но значение равно undefined.

так что код выглядит как-то

let num; // --- hoisted with value as undefined
setTimeout(() => {}, 1000)
console.log(useNum());

num = 10; // --- value is assigned here
function useNum(str) {
  return num + 1;
}

как вы знаете, java-скрипт является синхронным, то есть он выполняет каждую строку за раз, поэтому, когда мы вызываем метод useNum в это время, num будет неопределенным.

person Mujibur Rehman Ansari    schedule 15.02.2020
comment
Ваш код отличается от OP. Должно быть setTimeout(() => {console.log(useNum()}, 1000) - person David Callanan; 15.02.2020