Подтвердить что ты не робот

ES2017 - Async против дохода

Я запутался в текущем обсуждении добавления асинхронных функций и ключевого слова await к следующему EcmaScript.

Я не понимаю, зачем нужно ключевое слово async перед ключевым словом function.

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

await должен быть простым в нормальных функциях и функциях генератора без дополнительного маркера async.

И если мне нужно создать функцию, которая должна использоваться в качестве результата для await, я просто использую обещание.

Моей причиной для запроса является это хорошее объяснение, где приведен следующий пример:

async function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // some more logic
}

Он также может быть выполнен как нормальная функция, если выполнение функции будет ждать завершения функции отверстия до тех пор, пока все ожидания не будут выполнены.

function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // return because createUser() and getFacebookFriends() and maybe inviteFacebookFriends() finished their awaited result.

}

По моему мнению, выполнение всей функции выполняется до тех пор, пока не будет выполнен следующий тик (ожидание выполнения). Разница с Generator-Function заключается в том, что next() запускает и меняет значение объекта и поле done. Функция вместо этого просто возвращает результат, когда это будет сделано, и триггер является внутренним триггером функции, как цикл while.

4b9b3361

Ответ 1

Я не понимаю, зачем нужно ключевое слово async перед ключевым словом функции.

По той же причине, что мы имеем символ * перед функциями генератора: они отмечают функцию как экстраординарную. Они очень похожи в этом отношении - они добавляют визуальный маркер, который тело этой функции не запускается само по себе, но может быть чередованием произвольно с другим кодом.

  • * обозначает функцию генератора, которая всегда будет возвращать генератор, который может быть расширен (и остановлен) извне, потребляя его аналогично итератору.
  • async обозначает асинхронную функцию, которая всегда будет возвращать обещание, которое зависит от другого promises и выполнение которого одновременно с другими асинхронными операциями (и может быть отменено извне).

Верно, что ключевое слово не является строго необходимым, а вид функции можно определить, если в его теле появятся соответствующие ключевые слова (yield(*)/await), но это приведет к уменьшению количества поддерживаемого кода:

  • менее понятным, потому что вам нужно отсканировать все тело, чтобы определить вид
  • more errorprone, потому что легко сломать функцию, добавив/удалив эти ключевые слова без получения синтаксической ошибки.

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

Похоже, вы хотите, чтобы функция блокировки, которая представляет собой очень плохую идею, в параллельной настройке.

Ответ 2

Отметив функцию как async, вы сообщаете JS о возврате обещания.

Поскольку он всегда будет возвращать Promise, он также может ждать в promises внутри своего собственного блока. Представьте, что это как одна гигантская цепочка Promise - то, что происходит внутри функции, эффективно получает привязку к внутреннему блоку .then(), и то, что возвращается, является окончательным .then() в цепочке.

Например, эта функция...

async function test() {
  return 'hello world';
}

... возвращает обещание. Таким образом, вы можете выполнить его как один, .then() и все.

test().then(message => {
  // message = 'hello world'
});

Итак...

async function test() {
  const user = await getUser();
  const report = await user.getReport();
  report.read = true
  return report;
}

Примерно аналогичен...

function test() {
  return getUser().then(function (user) {
    return user.getReport().then(function (report) {
      report.read = true;
      return report;
    });
  });
}

В обоих случаях обратный вызов, переданный в test().then(), получит в качестве первого параметра report.

Генераторы (т.е. маркировка функции * и использование ключевого слова yield) - совсем другое понятие. Они не используют Promises. Они эффективно позволяют вам "прыгать" между различными частями вашего кода, получая результат изнутри функции, а затем перескакивая назад в эту точку и возобновляясь для следующего блока результатов.

Хотя они чувствуют себя несколько схожими (т.е. "останавливают" выполнение, пока что-то не происходит где-то в другом месте), async/await дает только эту иллюзию, потому что это противоречит внутреннему упорядочению исполнения Promise. Это не на самом деле ждет - это просто перетасовка, когда происходят обратные вызовы.

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

Линия еще размывается, потому что в текущий момент написания поддержка асинхронного/ждущего пугается; Chakracore поддерживает его изначально, и V8 скоро появится. В то же время транспилеры, подобные Babel, позволяют писать async/await и преобразовывать код в генераторы. Ошибочно заключить, что генераторы и async/await являются одинаковыми; они не... просто так получается, что вы можете угадать, как yield работает рядом с promises, чтобы получить аналогичный результат.

Обновление: ноябрь 2017

Node LTS теперь имеет встроенную поддержку async/await, поэтому вам не нужно будет использовать генераторы для имитации Promises.

Ответ 3

Все эти ответы дают правильные аргументы в пользу того, почему ключевое слово async - это хорошо, но ни один из них не упоминает реальную причину добавления в спецификацию.

Причина в том, что это был действительный JS pre-ES7

function await(x) {
  return 'awaiting ' + x
}

function foo() {
  return(await(42))
}

Согласно вашей логике, вернет ли foo() Promise{42} или "awaiting 42"? (возврат Promise нарушит совместимость)

Итак, ответ таков: await является регулярным идентификатором, и он рассматривается только как ключевое слово внутри асинхронных функций, поэтому их нужно каким-то образом маркировать.

Интересный факт: оригинальная спецификация предложила более легкий function^ foo() {} для синтаксиса асинхронного программирования.

Ответ 4

Причина ключевого слова async впереди проста, поэтому вы знаете, что возвращаемое значение будет преобразовано в обещание. Если нет ключевого слова, как это сделал бы интерпретатор. Я думаю, что это было впервые введено в С#, и EcmaScript берет на себя часть материала от TypeScript. TypeScript и С# задуманы Андерсом Хейльсбергом и похожи. скажем, у вас есть функция (для этого нужно просто выполнить асинхронную работу)

 function timeoutPromise() {  
     return (new Promise(function(resolve, reject) {
         var random = Math.random()*1000;
         setTimeout(
             function() {
                 resolve(random);
             }, random);
     }));
 }

эта функция заставит нас ждать случайного времени и вернуть Promise (если вы используете jQuery Promise, похожую на Отложенный) объект. Чтобы использовать эту функцию сегодня, вы должны написать что-то вроде этого

function test(){
    timeoutPromise().then(function(waited){
        console.log('I waited' + waited);
    });
}

И это прекрасно. Теперь попробуйте вернуть сообщение журнала

function test(){
    return timeoutPromise().then(function(waited){
        var message = 'I waited' + waited;
        console.log(message);
        return message; //this is where jQuery Deferred is different then a Promise and better in my opinion
    });
}

Хорошо, это неплохо, но в коде есть два оператора return и функция.

Теперь с async это будет выглядеть следующим образом:

  async function test(){
      var message = 'I waited' +  (await timeoutPromise());
      console.log(message);
      return message;
  }

Код короткий и встроенный. Если вы написали много .then() или. done() вы знаете, как нечитаемый код может получить.

Теперь почему ключевое слово async перед функцией. Ну, это означает, что возвращаемое значение не является тем, что возвращается. В теории вы могли бы написать это (это можно сделать в С# Я не знаю, разрешит ли js, так как это не сделано).

 async function test(wait){
     if(wait == true){
         return await timeoutPromise();
     }
     return 5;                
 }

вы видите, вы возвращаете число, но фактическое возвращение будет обещанием, которое вам не нужно использовать return new Promise(function(resolve, reject) { resolve(5);}; Поскольку вы не можете дождаться числа, Promise await test(false) будет генерировать исключение, а await test(true) не будет, если вы не указали асинхронный фронт.