Javascript 如何在顶层使用async/await?

Javascript 如何在顶层使用async/await?,javascript,node.js,async-await,ecmascript-2017,Javascript,Node.js,Async Await,Ecmascript 2017,我一直在看async/wait,在看了几篇文章之后,我决定自己测试一下。然而,我似乎无法理解为什么这不起作用: 异步函数main(){code> var value=wait Promise.resolve('Hey there'); console.log('内部:'+值); 返回值; } var text=main(); console.log('外部:'+文本); 控制台输出以下内容(节点v8.6.0): >外部:[反对承诺] >里面:嘿,那里 为什么函数中的日志消息会在之后执行?我认为

我一直在看
async
/
wait
,在看了几篇文章之后,我决定自己测试一下。然而,我似乎无法理解为什么这不起作用:

异步函数main(){code> var value=wait Promise.resolve('Hey there'); console.log('内部:'+值); 返回值; } var text=main(); console.log('外部:'+文本); 控制台输出以下内容(节点v8.6.0):

>外部:[反对承诺]

>里面:嘿,那里

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

是否有一种方法可以使用函数中返回的值而不使用
.then()
之后的
main()

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

因为
main
返回一个承诺;所有的
async
函数都可以

在顶层,您必须:

  • 使用永不拒绝的顶级
    async
    函数(除非您希望出现“未处理的拒绝”错误),或

  • 使用
    然后
    捕获
    ,或

  • (即将推出!)使用,这是一项在中已达到第3阶段的建议,允许在模块中顶级使用
    wait

  • #1-永不拒绝的顶级
    async
    函数 注意
    捕捉
    ;您必须处理承诺拒绝/异步异常,因为其他任何情况都不会发生;你没有电话可以转告。如果愿意,您可以通过
    catch
    函数(而不是
    try
    /
    catch
    语法)调用它的结果来执行此操作:

    …更简洁一点(我喜欢这样)

    当然,也可以不处理错误,只允许出现“未处理的拒绝”错误

    #2-
    然后
    捕获
    如果链或
    then
    处理程序中发生错误,将调用
    catch
    处理程序。(确保您的
    catch
    处理程序不会抛出错误,因为没有注册任何内容来处理这些错误。)

    的两个参数,然后

    main().then(
        text => {
            console.log(text);
        },
        err => {
            // Deal with the fact the chain failed
        }
    );
    
    再次注意,我们正在注册一个拒绝处理程序。但是在这个表单中,请确保
    then
    回调都不会抛出任何错误,没有注册任何内容来处理它们

    #3模块中的顶级
    等待
    
    您不能在非模块脚本的顶层使用
    wait
    ,但()允许您在模块的顶层使用它。这类似于使用顶级
    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
    }
    
    请注意,如果您这样做,从您的模块导入的任何模块都将等待,直到您等待的承诺解决;当对使用顶级
    wait
    的模块进行求值时,它基本上会向模块加载器返回一个承诺(就像
    async
    函数所做的那样),模块加载器会等待该承诺得到解决,然后再对依赖它的任何模块体进行求值。

    因为
    main()
    异步运行,所以它会返回一个承诺。您必须在
    then()
    方法中获得结果。因为
    then()
    也返回promise,所以必须调用
    process.exit()
    来结束程序

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

    这个问题的实际解决办法是以不同的方式处理

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

    解决方案是确保在应用程序的顶层只有一条JavaScript语句。如果在应用程序的顶部只有一条语句,则可以在任何其他位置自由使用async/Wait(当然要遵守正常语法规则)

    换句话说,将整个顶层封装在一个函数中,这样它就不再是顶层,从而解决了如何在应用程序的顶层运行异步/等待的问题—您不需要

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

    import {application} from './server'
    
    application();
    

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

    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!');
    }
    
    需要注意的主要问题是,生成的函数不是异步函数。因此,您不能直接在其内部使用术语
    wait

    但是如果您需要处理此文件中的承诺,那么有两种可能的方法:

  • 不要直接在函数内部使用
    wait
  • 不要使用
    wait
  • 选项1要求我们创建一个新的作用域(这个作用域可以是
    async
    ,因为我们可以控制它):

    选项2要求我们使用面向对象的promise API(不太漂亮但功能相同的promises工作范例)

    看到node添加对顶级
    wait
    的支持会很有趣

    已进入第3阶段,因此您的问题的答案是如何在顶层使用async/await?只需添加
    wait
    调用
    main()

    异步函数main(){ var value=wait Promise.resolve('Hey there'); console.log('内部:'+值); 返回值; } var text=await main(); console.log('外部:'+文本)
    或者只是:

    const text=wait Promise.resolve('Hey there');
    控制台
    
    import {application} from './server'
    
    application();
    
    // Amazing test file!
    console.log('Test!');
    
    function(require, __dirname, ... perhaps more top-level properties) {
      // Amazing test file!
      console.log('Test!');
    }
    
    // Amazing test file!
    // Create a new async function (a new scope) and immediately call it!
    (async () => {
      await new Promise(...);
      console.log('Test!');
    })();
    
    // Amazing test file!
    // Create some sort of promise...
    let myPromise = new Promise(...);
    
    // Now use the object-oriented API
    myPromise.then(() => console.log('Test!'));