我已经阅读了async/await,在阅读了几篇文章之后,我决定自己测试一下。然而,我似乎不明白为什么这行不通:
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = main();
console.log('outside: ' + text);
控制台输出以下内容(节点v8.6.0):
> outside: [object Promise]
> inside:嘿,大家好
为什么函数内部的日志消息之后执行?我认为创建async/await的原因是为了使用异步任务执行同步执行。
是否有一种方法可以使用函数内部返回的值,而不使用main()后的.then() ?
如果您的唯一目标是为了测试目的控制混合了其他代码的异步代码的执行顺序,那么您可以将整个顶级代码包装在定义为异步函数的立即调用函数表达式(IIFE)中。在问题的示例中,在调用main()之前添加await。
当您的代码不在异步函数中或不在模块的顶层主体中时,可以使用此模式。换句话说,如果你只是在一个js文件中测试一堆代码,并使用Live Server、RunJs或任何其他类型的JavaScript工具来观察控制台窗口,将所有代码包装在定义为异步的IIFE中,当你想在执行下一行之前等待异步代码完成时,使用await关键字。
let topLevelIIFE = (async () => {
异步函数main() {
var value = await承诺。解决('嘿');
Console.log ('inside: ' + value);
返回值;
}
Var文本=等待main();
Console.log ('outside: ' + text);
}) ()
在Chrome DevTools或其他行为类似的浏览器REPL工具的REPL中运行IIFE主体中指定的代码时,您不需要使用此模式。
在当前答案的基础上提供一些进一步的信息:
node.js文件的内容目前以类似字符串的方式连接起来,以形成一个函数体。
例如,如果你有一个文件test.js:
// Amazing test file!
console.log('Test!');
然后node.js会秘密地连接一个函数,看起来像这样:
function(require, __dirname, ... perhaps more top-level properties) {
// Amazing test file!
console.log('Test!');
}
需要注意的主要事情是,得到的函数不是一个异步函数。所以你不能在里面直接使用await这个词!
但是如果你需要使用这个文件中的承诺,那么有两种可能的方法:
不要在函数中直接使用await
完全不要使用await
选项1要求我们创建一个新的作用域(这个作用域可以是异步的,因为我们可以控制它):
// 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!'));
看到节点添加对顶级await的支持会很有趣!
其他解决方案缺乏POSIX兼容性的一些重要细节:
你需要…
成功时报告0退出状态,失败时报告非0退出状态。
向标准输出流发出错误。
#!/usr/bin/env node
async function main() {
// ... await stuff ...
}
// POSIX compliant apps should report an exit status
main()
.then(() => {
process.exit(0);
})
.catch(err => {
console.error(err); // Writes to stderr
process.exit(1);
});
如果使用command等命令行解析器,则可能不需要main()。
例子:
#!/usr/bin/env node
import commander from 'commander'
const program = new commander.Command();
program
.version("0.0.1")
.command("some-cmd")
.arguments("<my-arg1>")
.action(async (arg1: string) => {
// run some async action
});
program.parseAsync(process.argv)
.then(() => {
process.exit(0)
})
.catch(err => {
console.error(err.message || err);
if (err.stack) console.error(err.stack);
process.exit(1);
});
2021年的答案:你现在可以在当前稳定版本的节点中使用顶级等待
上面的大多数答案都有点过时或非常冗长,所以这里有一个关于节点14的快速示例。
创建一个名为runme.mjs的文件:
import * as util from "util";
import { exec as lameExec } from "child_process";
const exec = util.promisify(lameExec);
const log = console.log.bind(console);
// Top level await works now
const { stdout, stderr } = await exec("ls -la");
log("Output:\n", stdout);
log("\n\nErrors:\n", stderr);
运行node runme.mjs
Output:
total 20
drwxr-xr-x 2 mike mike 4096 Aug 12 12:05 .
drwxr-xr-x 30 mike mike 4096 Aug 12 11:05 ..
-rw-r--r-- 1 mike mike 130 Aug 12 12:01 file.json
-rw-r--r-- 1 mike mike 770 Aug 12 12:12 runme.mjs
Errors: