Как я могу использовать async/wait на верхнем уровне?
Я перешел через async/wait, и, пройдя несколько статей, я решил сам проверить. Тем не менее, я, похоже, не могу обернуть вокруг себя, почему это не работает:
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = main();
console.log('outside: ' + text)
Консоль выводит следующее (node v8.6.0):
> снаружи: [object Promise]
> внутри: Эй там
Почему сообщение журнала внутри функции выполняется потом? Я думал, что причина async/await была создана для выполнения синхронного выполнения с использованием асинхронных задач.
Можно ли использовать значение, возвращаемое внутри функции, без использования .then()
после main()
?
Ответы
Ответ 1
Кажется, я не могу понять, почему это не работает.
Потому что main
возвращает обещание; все функции async
выполняют.
На верхнем уровне вы должны либо:
Используйте функцию верхнего уровня async
, которая никогда не отклоняет (если вы не хотите ошибок "необработанное отклонение"), или
Используйте then
и catch
или
(Скоро!) Используйте верхнего уровня await
, предложение, которое достигло стадии 3 в процессе process, которое позволяет использовать на верхнем уровне await
в модуль.
# 1 - функция верхнего уровня async
, которая никогда не отклоняет
(async () => {
try {
var text = await main();
console.log(text);
} catch (e) {
// Deal with the fact the chain failed
}
})();
Обратите внимание на catch
; вы должны обрабатывать обещания отклонения/асинхронные исключения, так как больше ничего не происходит; у вас нет звонящего, чтобы передать их. Если вы хотите, вы можете сделать это в результате вызова через функцию catch
(а не синтаксис try
/catch
):
(async () => {
var text = await main();
console.log(text);
})().catch(e => {
// Deal with the fact the chain failed
});
... что более кратко (мне нравится по этой причине).
Или, конечно же, не обрабатывайте ошибки, а просто допускайте ошибку "необработанный отказ".
# 2 - then
и catch
main()
.then(text => {
console.log(text);
})
.catch(err => {
// Deal with the fact the chain failed
});
Обработчик catch
будет вызван, если в цепочке или в вашем обработчике then
возникнут ошибки. (Убедитесь, что ваш обработчик catch
не выдает ошибки, так как для их обработки не зарегистрировано ничего.)
Или оба аргумента then
:
main().then(
text => {
console.log(text);
},
err => {
// Deal with the fact the chain failed
}
);
Снова обратите внимание, что мы регистрируем обработчик отклонения. Но в этой форме убедитесь, что ни один из ваших обратных вызовов then
не выдает никаких ошибок, ничего не зарегистрировано для их обработки.
# 3 верхнего уровня await
в модуле
Вы не можете использовать await
на верхнем уровне немодульного скрипта, но предложение верхнего уровня await
(Этап 3) позволяет использовать его на верхний уровень модуля. Это похоже на использование функции-обертки верхнего уровня async
(№1 выше) в том смысле, что вы не хотите, чтобы ваш код верхнего уровня отклонял (выдавал ошибку), потому что это приведет к необработанной ошибке отклонения. Поэтому, если вы не хотите, чтобы этот необработанный отказ отклонялся, когда что-то пошло не так, как в случае С# 1, вы захотите обернуть свой код в обработчик ошибок:
// In a module, once the top-level 'await' proposal lands
try {
var text = await main();
console.log(text);
} catch (e) {
// Deal with the fact the chain failed
}
Ответ 2
Фактическое решение этой проблемы - это подход к ней по-разному.
Вероятно, ваша цель - это своего рода инициализация, которая обычно происходит на верхнем уровне приложения.
Решение состоит в том, чтобы убедиться, что на самом верхнем уровне вашего приложения существует только одна заявка на JavaScript. Если у вас есть только один оператор в верхней части приложения, то вы можете использовать async/await в любой другой точке в любом месте (естественно, при условии соблюдения нормальных синтаксических правил)
Иными словами, оберните весь свой верхний уровень функцией, чтобы он больше не был верхним уровнем и решает вопрос о том, как запускать async/await на верхнем уровне приложения - вы этого не делаете.
Это то, на что должен выглядеть верхний уровень вашего приложения:
import {application} from './server'
application();
Ответ 3
Top-Level await
переместились на 3 стадию, так что ответ на ваш вопрос Как я могу использовать асинхронный/поджидает на высшем уровне? это просто добавить await
вызова main()
:
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = await main();
console.log('outside: ' + text)
Или просто:
const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)
Имейте в виду, что он по-прежнему доступен только в [email protected].
Ответ 4
Чтобы дать некоторую дополнительную информацию поверх текущих ответов:
Содержимое файла node.js
в настоящее время объединяется в виде строки, чтобы сформировать тело функции.
Например, если у вас есть файл test.js
:
// Amazing test file!
console.log('Test!');
Затем node.js
тайно объединит функцию, которая выглядит следующим образом:
function(require, __dirname, ... a bunch more top-level properties) {
// Amazing test file!
console.log('test!');
}
Главное, на что следует обратить внимание, это то, что результирующая функция НЕ является асинхронной функцией. Таким образом, вы не можете использовать термин await
прямо внутри него!
Но, скажем, вам нужно работать с обещаниями в этом файле, тогда есть два возможных метода:
- Не используйте
await
непосредственно внутри функции - Не пользуйтесь,
await
Вариант 1 требует, чтобы мы создали новую область (и ЭТА область может быть async
, потому что у нас есть контроль над ней):
// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
await new Promise(...);
console.log('Test!');
})();
Вариант 2 требует от нас использования объектно-ориентированного API обещаний (менее привлекательная, но в то же время функциональная парадигма работы с обещаниями)
// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);
// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));
Я лично надеюсь, что, если это будет работать, node.js по умолчанию объединит код в async
функцию. Это избавило бы от этой головной боли.
Ответ 5
Поскольку main()
работает асинхронно, он возвращает обещание. Вы должны получить результат в методе then()
. И поскольку then()
возвращает обещание, вы должны вызвать process.exit()
чтобы завершить программу.
main()
.then(
(text) => { console.log('outside: ' + text) },
(err) => { console.log(err) }
)
.then(() => { process.exit() } )