如何在顶层使用 async/await?

IT技术 javascript node.js async-await ecmascript-2017
2021-02-08 18:08:17

我一直在翻阅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):

> 外面:【对象Promise】

> 内部:嘿那里

为什么函数内部的日志消息会在之后执行?我认为创建async/的原因await是为了使用异步任务执行同步执行。

有没有办法可以在不使用.then()after 的情况下使用函数内部返回的值main()

6个回答

我似乎无法理解为什么这不起作用。

因为main返回一个Promise;所有async功能都可以。

在顶层,您必须:

  1. 使用async从不拒绝的顶级函数(除非您想要“未处理的拒绝”错误),或

  2. 使用thencatch, 或

  3. (即将推出!)使用top-levelawait,该提案已在流程达到第 3 阶段,允许await在module中进行顶级使用

#1 -async从不拒绝的顶级函数

(async () => {
    try {
        var text = await main();
        console.log(text);
    } catch (e) {
        // Deal with the fact the chain failed
    }
})();

注意catch; 必须处理Promise拒绝/异步异常,因为没有其他事情要做;您没有可以将它们传递给的呼叫者。如果您愿意,您可以根据通过catch函数(而不是try/catch语法)调用它的结果来执行此操作

(async () => {
    var text = await main();
    console.log(text);
})().catch(e => {
    // Deal with the fact the chain failed
});

...更简洁一点(我喜欢这个原因)。

或者,当然,不要处理错误而只允许“未处理的拒绝”错误。

#2 -thencatch

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回调都不会引发任何错误,也没有注册任何内容来处理它们。

#3awaitmodule中的顶层

您不能await在非module脚本的顶层使用await,但顶层提案第 3 阶段)允许您在module的顶层使用它。它类似于使用顶级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
}

请注意,如果您这样做,从您的module导入的任何module都将等到您的Promiseawait解决;await评估使用顶级的module时,它基本上会向module加载器返回一个Promise(就像一个async函数一样),它会等到该Promise得到解决,然后再评估依赖于它的任何module的主体。

@SurajShrestha - 不。但这不是问题。:-)
2021-03-24 18:08:17
将其视为Promise现在解释了为什么该函数会立即返回。我尝试制作一个顶级匿名异步函数,现在我得到了有意义的结果
2021-03-27 18:08:17
@Felipe:是的,async/awaitPromise周围的语法糖(好的糖 :-) )。你不只是想着它为返回一个Promise; 确实如此。详情。)
2021-04-02 18:08:17
@LukeMcGregor - 我在上面都展示了,async首先是 all-选项。对于顶级函数,我可以通过任何一种方式看到它(主要是因为async版本上有两级缩进)。
2021-04-05 18:08:17
@Felipe - 由于顶级await提案已达到第 3 阶段,我已经更新了答案。:-)
2021-04-07 18:08:17

顶级await已移至第 3 阶段,因此您的问题的答案如何在顶级使用 async/await?只是将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)

兼容性

--harmony-top-level-await 对我不起作用 我在节点 14
2021-03-14 18:08:17
@QuintenCabo 这可能是因为您没有使用 ES module。为确保 Node 处于module模式,添加"type": "module"package.json.
2021-03-27 18:08:17

2021 答案:您现在可以在当前稳定版本的 node 中使用顶级 await

上面的大多数答案都有些过时或非常冗长,所以这里有一个节点 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:
我正在使用 Next.js,这对我很有帮助:stackoverflow.com/a/68339259/470749
2021-03-12 18:08:17
感谢更新!
2021-03-31 18:08:17

要在当前答案之上提供更多信息:

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直接在它里面使用这个词

但是如果你需要在这个文件中使用 promises,那么有两种可能的方法:

  1. 不要await 直接在函数内部使用
  2. 不要使用 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 要求我们使用面向对象的 promise API(使用 promise 的不太漂亮但功能相同的范例)

// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);

// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));

看到节点添加对顶级的支持会很有趣await

[Node 在 v13.3 中的标志后面添加了对顶级 await 的支持] stackoverflow.com/questions/59585793/...)。
2021-03-29 18:08:17

您现在可以在Node v13.3.0 中使用顶级 await

import axios from "axios";

const { data } = await axios.get("https://api.namefake.com/");
console.log(data);

--harmony-top-level-await标志运行它

node --harmony-top-level-await index.js

该版本更新日志没有提到任何关于顶级等待的内容,似乎支持从 v13.3 开始的标志
2021-03-27 18:08:17