如何在顶层使用async / await?

时间:2017-10-01 18:55:15

标签: javascript node.js async-await ecmascript-2017

我一直在浏览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):

  

>外:[对象承诺]

     

>里面:嘿那里

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

有没有办法在.then()后使用main()之后使用函数内返回的值?

11 个答案:

答案 0 :(得分:103)

  

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

因为Personid Forename Surname Groupid count 1 John Bloggs 1 2 2 Josh Bloggs 1 2 3 Bert Bloggs 1 2 4 Owen Jones 2 1 5 Jack Rose 3 1 返回一个承诺;所有main函数都可以。

在顶级,您必须:

  1. 使用永不拒绝的顶级async函数,或

  2. 使用asyncthen

  3. #1 - 永不拒绝的顶级catch函数

    async

    注意(async () => { try { var text = await main(); console.log(text); } catch (e) { // Deal with the fact the chain failed } })(); ;你必须处理承诺拒绝/异步异常,因为没有别的东西;你没有调用者将它们传递给。如果您愿意,可以通过catch函数(而不是catch / try语法)调用它的结果:

    catch

    ......这更简洁一些(因为这个原因,我喜欢它)。

    #2 - (async () => { var text = await main(); console.log(text); })().catch(e => { // Deal with the fact the chain failed }); 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 } ); 回调都没有抛出任何错误,没有注册任何错误来处理它们。

答案 1 :(得分:4)

您现在可以在Node v14.3.0

中使用顶级等待
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

答案 2 :(得分:2)

解决此问题的实际方法是采用不同的方法。

您的目标可能是某种初始化,通常发生在应用程序的顶层。

解决方案是确保应用程序的顶层只有一个JavaScript语句。如果您的应用程序顶部只有一条语句,那么您可以在其他任何地方随意使用async / await(当然,这取决于常规语法规则)

采用另一种方法,将整个顶层包装在一个函数中,以使其不再是顶层,从而解决了如何在应用程序的顶层运行异步/等待的问题-您无需这样做。 / p>

这是应用程序顶层的外观:

import {application} from './server'

application();

答案 3 :(得分:1)

要在当前答案的基础上提供更多信息:

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

但是说您需要在此文件中使用Promise,那么有两种可能的方法:

  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!'));

我个人希望,如果可行,默认情况下,node.js将代码连接到async函数中。这样可以摆脱这种头痛。

答案 4 :(得分:1)

Top-Level 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)

请记住,它仍然仅在Webpack@v5.0.0-alpha.15中可用。

答案 5 :(得分:1)

节点-
您可以在REPL中运行node --experimental-repl-await。我对脚本不太确定。

Deno -
Deno已经内置了它。

答案 6 :(得分:1)

我喜欢这种巧妙的语法从入口点执行异步工作

void async function main() {
  await doSomeWork()
  await doMoreWork()
}()

答案 7 :(得分:0)

由于main()以异步方式运行,因此返回一个promise。您必须使用then()方法获得结果。由于then()也会返回承诺,因此您必须致电process.exit()以结束该计划。

main()
   .then(
      (text) => { console.log('outside: ' + text) },
      (err)  => { console.log(err) }
   )
   .then(() => { process.exit() } )

答案 8 :(得分:0)

顶级等待是即将到来的EcmaScript标准的一项功能。目前,您可以在TypeScript 3.8(目前为RC版本)中开始使用它。

如何安装TypeScript 3.8

您可以使用以下命令开始使用TypeScript 3.8 by installing it from npm

$ npm install typescript@rc

这时,您需要添加rc标签以安装最新的Typescript 3.8版本。

答案 9 :(得分:0)

其他解决方案缺乏 POSIX 合规性的一些重要细节:

你需要...

  • 成功时报告 0 退出状态,失败时报告非零状态。
  • stderr 输出流发出错误。
#!/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);
    });

如果您使用像 commander 这样的命令行解析器,您可能不需要 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);
  });

答案 10 :(得分:0)

在 NodeJS 14.8+ 中,您可以使用顶级 await 模块(#3 解决方案)。您也可以将 .js 重命名为 .mjs(ES 模块)而不是 .js(.cjs CommonJS)。