Почему языковой дизайн Javascript не включает ожидание разрешения переменных перед их использованием? - PullRequest
0 голосов
/ 21 февраля 2019

В Javascript вы должны явно указать своему коду, чтобы он ожидал разрешения переменной, прежде чем использовать ее с ключевым словом await, например:

let x = await doSomethingAsynchronous()
console.log(`The result is ${x.result}`)

Если "await" специально не включенJavascript с радостью попытается получить доступ к x.result до разрешения x и, следовательно, выдаст ошибку.Почему это по умолчанию?Как часто программисты хотят использовать переменную до ее разрешения?Почему компилятор Javascript не вставляет await непосредственно перед использованием неразрешенной переменной?

Я совершенно новичок в Javascript, поэтому извините, если ответ очевиден, и заранее благодарен за вашу помощь.

Сноски -

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

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Есть две основные причины, по которым я могу придумать:

2) doSomethingAsynchronous() возвращает Обещание , и вполне допустимо и принято делать что-то с этим Обещанием, кромеawait it.

Вот один пример:

const promises = [];
for ( let i = 0; i < 100; i++ )
  promises.push( doSomethingAsynchronous( ) );
const results = await Promise.all( promises );

Это запустит все 100 асинхронных задач одновременно и ожидает только в конце;очень отличается от наличия await внутри цикла, который будет ждать каждого Обещания перед началом следующей задачи.

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

2) Это значительно усложнит чтение / запись JavaScript.Рассмотрим следующий код:

setTimeout( function ( ) { console.log( 'FOO' ) }, 0 );
console.log( x.result );

Поскольку JavaScript запускает код до завершения, прежде чем цикл событий продолжается, ясно, что console.log( x.result ); запускается раньше, чем console.log( 'FOO' );.Если бы JavaScript имел неявное await, вы бы не знали, является ли x.result синхронным или нет, и это означало бы, что порядок этих журналов станет недетерминированным.В целом, знание порядка, в котором будет выполняться ваш код, очень важно, и невозможность определить, правильно ли определен порядок или нет, затруднит программирование на JavaScript.

Вот пример:

(async _ => {

  const x = new Promise( resolve => setTimeout( _ => resolve( { foo: 'bar' } ), 1000 ) );
  setTimeout( function ( ) { console.log( '2) async' ) }, 0 );
  x.foo;
  console.log( '1) Sync' );

})();

Поскольку x.foo является синхронной операцией (доступ к свойству Promise foo будет просто неопределенным, но это только для демонстрации, потерпите меня)журналов, как и ожидалось, но если в этом коде было неявное ожидание (которое мы можем смоделировать с помощью (await x):

(async _ => {

  const x = new Promise( resolve => setTimeout( _ => resolve( { foo: 'bar' } ), 1000 ) );
  setTimeout( function ( ) { console.log( '2) async' ) }, 0 );
  (await x).foo; // Simulate implicit await
  console.log( '1) Sync??' ); 

})();

Журналы происходят в обратном порядке (или потенциально недетерминированный порядок для более коротких таймеров).

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

0 голосов
/ 21 февраля 2019

Как часто программисты хотят использовать переменную до ее разрешения?

Довольно редко на самом деле.Я могу вспомнить только один случай, когда я закомментировал await, это было что-то вроде:

 const result = await database();

 if(check)
   /*await*/ notifyUser();

 return result;

Мне это было нужно в этом случае, так как я не против, если уведомление приходит после того, как ответ получен.И я все еще оставил комментарий, чтобы будущие читатели получили асинхронность.Так что да, если было бы противоположное ключевое слово, я (и другие) сэкономил бы много печатать.

[Тогда], почему это [не ожидает] по умолчанию?

Я вижу только две причины:

Если ожидание будет неявным, вы не сможете определить из кода, как он будет себя вести, вызов функции может привести к тому, что выполнение функции приведет костановка и вы получите неожиданный порядок выполнения (трудно отладить = плохо):

async function stuff() {
 a();
 console.log("a");
 b();
 console.log("b");
}

stuff(); stuff(); // a, a, b, b ... what the ... ?

Использование await является явным, вы знаете, где async function может остановиться.

Кроме того, движокпридется проверять ответ на каждый вызов функции и каждый вызов метода, если он возвращает обещание:

 promise() // await this?
  .then(/*...*/); // or this?
 maybe(); // or this?

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

Однако я не являюсь частью ES Comitee, чтобы получитьконкретный ответ спросить их, я могу только догадываться об их причинах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...