Это сложная тема c при переходе с других языков программирования. Используя вашу терминологию, «нормальная» функция похожа на синхронную функцию.
Я бы порекомендовал MDN документы для ожидания . Прочитайте эту страницу и затем запустите пример f1
- я включил его ниже с парой улучшений:
- Я добавил метки времени в console.log, чтобы время стало более очевидным
- Я добавил
console.log
операторы непосредственно до и после вызова f1()
.
Ключевое слово await
не означает ожидание (или блокирование) в асинхронном режиме c функция. Он разделяет поток выполнения, приостанавливая функцию f1
(которая будет возобновлена примерно через 2 секунды) и возвращая Promise вызывающей стороне, которая позволяет вызывающей функции asyn c выбирать, хочет ли он ожидать результата функция asyn c или нет. В приведенном ниже коде мы распечатываем результат вызова f1()
, но мы решили не ожидать отложенного результата, а просто продолжаем переход к следующему console.log
.
Запустите этот код в Node.js :
///////////////////////////////////////////////////////////////////////
// This is just setting up timestamps for console.log
///////////////////////////////////////////////////////////////////////
const oldlog = console.log;
console.log = function () {
var args = [].slice.call(arguments);
oldlog.apply(console.log,[getTimestamp()].concat(args));
};
const getTimestamp = () => '[' + (new Date()).toISOString() + ']';
///////////////////////////////////////////////////////////////////////
// Real code starts here
///////////////////////////////////////////////////////////////////////
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
console.log('enter f1');
const x = await resolveAfter2Seconds(10);
console.log('exit f1, x =', x);
return x;
}
console.log('before f1');
const y = f1();
console.log('after f1, y =', y);
При запуске это приведет к чему-то вроде следующего:
[2020-03-03T01:48:50.716Z] before f1
[2020-03-03T01:48:50.719Z] enter f1
[2020-03-03T01:48:50.720Z] after f1, y = Promise { <pending> }
[2020-03-03T01:48:52.725Z] exit f1, x = 10
Обратите особое внимание, что мы видим after f1
log до , который мы видим exit f1
журнал. Поток выполнения был разделен и f1()
был приостановлен, а вызывающий f1()
продолжил. Выполнение f1()
возобновилось примерно через 2 секунды.
Теперь сравните это с тем, что произойдет, если вместо await
мы получим результат от вызова f1()
. Обратите внимание, что поскольку мы сейчас используем await
, мы должны заключить код в async
(на самом деле это асин c IIFE ), поскольку await
можно использовать только внутри функции async
.
// console.log('before f1');
// const y = f1();
// console.log('after f1, y =', y);
(async () => {
console.log('before f1');
const y = await f1();
console.log('after f1, y =', y);
})();
Теперь вывод выглядит следующим образом:
[2020-03-03T02:19:18.122Z] before f1
[2020-03-03T02:19:18.124Z] enter f1
[2020-03-03T02:19:20.130Z] exit f1, x = 10
[2020-03-03T02:19:20.130Z] after f1, y = 10
Обратите внимание, что теперь, поскольку вызывающий абонент решил дождаться результата вызова f1()
, мы видим after f1
и exit f1
журналы в обратном порядке (и в «обычном» порядке, используя вашу терминологию). И теперь результат f1()
равен 10, а не ожидающему выполнения Обещанию.
Итак, это немного сложный материал, и я призываю больше чтения и экспериментов, чтобы разобраться с ним. Это выглядит сложно, но на самом деле теперь написать асинхронный код JavaScript проще, чем до введения async / await в язык.