Как ждать асинхронную функцию?

Мое дело:

let waiting = function () {
  return new Promise(resolve => {
    console.log('awaiting...');
    
    setTimeout(function () {
      resolve();
    }, 1000)
  });
};

let waitingAsync = async function () {
  console.log('start...');

  await waiting();

  console.log('stop...');
};

waitingAsync();
console.log('done...');

В коде есть две вещи, которые я не понимаю:

Первый:

await waiting();

waiting является синхронной функцией (потому что она не имеет async ключевое слово). Итак, почему я могу ждать синхронную функцию?

Второй:

Почему не мог done... сообщение будет ждать после завершения waitingAsync функционировать?

И главный вопрос: waitingAsync является асинхронной функцией, почему await ключевое слово не требуется при вызове? Просто waitingAsync() вместо await waitingAsync(),

Если я могу ждать waitingAsync(), done... сообщение будет напечатано последним.

5 ответов

Решение

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

async и обычные функции не отличаются от вызывающего. async просто возвращает обещание, не возвращая его явно при вызове. Результат waitingAsync() Звонок это обещание. Результат waiting() Вызов тоже обещание, поэтому оно не является "синхронным".

Согласно спецификации, как обещания, так и не обещания могут быть awaitредактор Необещания преобразуются в обещания с Promise.resolve(),

console.log('done...') нельзя ожидать, потому что он не вызывается внутри async функция. И это не должно быть awaitЭд, потому что это не возвращает обещание, но undefined, awaitэто было бы возможно в течение async функция. Эти await использования равны и в равной степени бесполезны, все, что они делают, это задержка на 1 такт:

async function ... {
  ...
  await console.log('done...');
}

async function ... {
  ...
  console.log('done...');
  await undefined;
}

async function ... {
  ...
  await Promise.resolve(console.log('done...'));
}

async Функция возвращает обещание или, когда она использует await ключевое слово, оно должно ждать асинхронную функцию, будь то обещание или другое async функция. В вашем коде waiting() это функция, которая возвращает обещание Затем, await waiting() правильно (так как он ожидает асинхронной функции).

async функция вызывается как другая базовая функция называется. Вы можете пометить функцию как асинхронную, если хотите использовать ее как асинхронную функцию и использовать ключевое слово "await". "Готово..." печатается, потому что, когда вы звоните asyncFunction(), это должно await до тех пор waiting promise закончен. Но программа не останавливается и продолжает показывать done..., Если вы хотите подождать, может быть, вы можете использовать asyncFunction().then( () => console.log('done...') )

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

С другой стороны, когда вы объявляете async функции, ее возвращаемое значение будет возвращено как Обещание, и любая ошибка, сгенерированная из него, будет приведена к отклоненному Обещанию.

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

это только о async а также awaitесть, просто автоматическое приведение к обещаниям. Вам не нужно, чтобы код, использующий await и async, был действительно асинхронным (хотя, на самом деле, он не очень полезен).

Быстрая демонстрация:

//Will return the string 'Promise' if called through `await`
function getPromise(){
    return Promise.resolve('Promise');
}

//Casted to Promise.reject thrught await 
function throwError(){
    return Promise.reject('error'); 
}

function get(){
    return 'something simple'; 
}

async function getAsync() {
    var response = await getPromise();
    return response;
}
//await will cast the rejected Promise to an error
async function getErrorAsync() {
    var response = await throwError();
    return response;
}

async function simpleGet(){
    return get();
}

async function redundantGet(){
    return await get();
}

    async function catchTheError(){
      try{
          await throwError();
      }       
      catch(e){
         console.log('an error: ' + e );
      }
       return 'whatever';
 }

getAsync().then( console.log ); //Promise
getErrorAsync().catch( console.log ); //error
simpleGet().then( console.log ); //something simple
redundantGet().then( console.log ); //something simple
catchTheError(); //will log 'an error: error'.

Так:

ожидание - синхронная функция (потому что у нее нет ключевого слова async). Итак, почему я могу ждать синхронную функцию?

Потому что ты можешь. Единственная вещь await делает, чтобы разрешить обещание реальных ценностей и ошибок. Вам на самом деле не нужна функция для возврата обещания.

Почему не удалось сделать... после завершения функции waitAsync можно ожидать сообщения?

async а также await только заставляет ваш код вести себя так, как если бы он был синхронным asyncобъявленные функции. Твоя последняя console.log('done') вне любого async функция, поэтому она будет просто записана в журнал до завершения этой функции, поскольку она асинхронная.

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

Так как async ключевое слово преобразует значения в обещания и позволяет использовать await- и больше ничего. На самом деле, так как вы можете использовать только await внутри async функции... вы не можете ожидать async функции для вызова awaitВам понадобится бесконечное количество asyncфункции:-D.

Async ключевое слово, используемое для указания того, что функция будет экземпляром AsyncFunction так что вернусь Promise,

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


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

В вашем сообщении много хороших вопросов, которые могут помочь понять асинхронные вызовы.


Прежде чем приступить к делу, стоит обратить внимание на несколько вещей.
Любой читатель фрагмента кода

      let waiting = function () {
  return new Promise(resolve => {
    console.log('awaiting...');
    setTimeout(function () { resolve(); }, 1000);
  });
};

let waitingAsync = async function () {
  console.log('start...');
  await waiting();
  console.log('stop...');
};

waitingAsync();
console.log('done...');

может ошибочно полагать, что результат будет

      start...
awaiting...
stop...
done...

в то время как - как вы уже отметили - печатается перед stop....

Причина в том, что waitingAsync();это вызов асинхронной функции, а console.log('done...'); это просто нормальный последовательный / синхронный оператор, который выполняется сразу.


Вопрос 1:

является синхронная функция (потому что он не имеет async ключевое слово) [?]

Ответ :
Неверно.Функция является синхронной - она возвращает Promise .


Вопрос 2:

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

Ответ :
Потому что не асинхронный.
(Он не возвращает никаких обещаний.)


Вопрос 3:

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

Ответ :
Ну, в вашем примере не возвращает никакого значения. - Если бы возвращать значение , которое вы заботитесь о, то вам нужно будет ждать его , чтобы получить его. ( Hello world! в моем фрагменте стека ниже.)


Вопрос 4:

Если я могу подождать waitingAsync(), [the] done...сообщение будет напечатано последним. [?]

Ответ :
Это зависит от того, что именно вы имеете в виду. - См. Мой фрагмент стека ниже! Пока doneсообщение находится в том же обратном вызове, что и вызов, ответ - Да!
Но если поставить console.log('done...') после асинхронного вызова, который завершает await waitingAsync()тогда ответ - нет!


При запуске приведенного ниже фрагмента обратите внимание на порядок вывода!
Также обратите внимание , как она занимает 1400 мс для Promise resolved! показывать.

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

Урок на вынос

Никогда не помещайте последовательный / синхронный код после и вне вызова асинхронной функции!

Если вы это сделаете, вы просто запутаете себя. - И даже если вы не запутаетесь, другие читатели вашего кода почти наверняка будут.

Другие вопросы по тегам