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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46515764/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:28:49  来源:igfitidea点击:

How can I use async/await at the top level?

javascriptnode.jsasync-awaitecmascript-2017

提问by Felipe

I have been going over async/awaitand after going over several articles, I decided to test things myself. However, I can't seem to wrap my head around why this does not work:

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

The console outputs the following (node v8.6.0) :

控制台输出以下内容(节点 v8.6.0):

> outside: [object Promise]

> inside: Hey there

> 外面:【对象承诺】

> 内部:嘿那里

Why does the log message inside the function execute afterwards? I thought the reason async/awaitwas created was in order to perform synchronous execution using asynchronous tasks.

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

Is there a way could I use the value returned inside the function without using a .then()after main()?

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

回答by T.J. Crowder

I can't seem to wrap my head around why this does not work.

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

Because mainreturns a promise; all asyncfunctions do.

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

At the top level, you must either:

在顶层,您必须:

  1. Use a top-level asyncfunction that never rejects (unless you want "unhandled rejection" errors), or

  2. Use thenand catch, or

  3. (Coming soon!)Use top-level await, a proposal that has reached Stage 3 in the processthat allows top-level use of awaitin a module.

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

  2. 使用thencatch, 或

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

#1 - Top-level asyncfunction that never rejects

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

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

Notice the catch; you musthandle promise rejections / async exceptions, since nothing else is going to; you have no caller to pass them on to. If you prefer, you could do that on the result of calling it via the catchfunction (rather than try/catchsyntax):

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

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

...which is a bit more concise (I like it for that reason).

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

Or, of course, don't handle errors and just allow the "unhandled rejection" error.

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

#2 - thenand catch

#2 -thencatch

main()
    .then(text => {
        console.log(text);
    })
    .catch(err => {
        // Deal with the fact the chain failed
    });

The catchhandler will be called if errors occur in the chain or in your thenhandler. (Be sure your catchhandler doesn't throw errors, as nothing is registered to handle them.)

catch如果发生在链中或在你的错误处理程序将调用then处理程序。(确保您的catch处理程序不会抛出错误,因为没有注册来处理它们。)

Or both arguments to then:

或两个论据then

main().then(
    text => {
        console.log(text);
    },
    err => {
        // Deal with the fact the chain failed
    }
);

Again notice we're registering a rejection handler. But in this form, be sure that neither of your thencallbacks doesn't throw any errors, nothing is registered to handle them.

再次注意我们正在注册一个拒绝处理程序。但是在这种形式中,请确保您的then回调都不会抛出任何错误,也没有注册任何内容来处理它们。

#3 top-level awaitin a module

#3await模块中的顶层

You can't use awaitat the top level of a non-module script, but the top-level awaitproposal(Stage 3) allows you to use it at the top level of a module. It's similar to using a top-level asyncfunction wrapper (#1 above) in that you don't want your top-level code to reject (throw an error) because that will result in an unhandled rejection error. So unless you want to have that unhandled rejection when things go wrong, as with #1, you'd want to wrap your code in an error handler:

您不能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
}

Note that if you do this, any module that imports from your module will wait until the promise you're awaiting settles; when a module using top-level awaitis evaluated, it basically returns a promise to the module loader (like an asyncfunction does), which waits until that promise is settled before evaluating the bodies of any modules that depend on it.

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

回答by lautaro.dragan

Top-Level awaithas moved to stage 3, so the answer to your question How can I use async/await at the top level?is to just add awaitthe call to main():

顶级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)

Or just:

要不就:

const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)

Do keep in mind that it's still only available in [email protected].

请记住,它仍然只在[email protected]可用。

If you're using TypeScript, it landed in 3.8.

如果您使用的是 TypeScript,它会出现在 3.8 中

v8 has added supportin modules.

v8在模块中增加了支持

It's also supported by Deno(as commented by gonzalo-bahamondez).

它也通过支持杰诺(由贡萨洛- bahamondez评论)。

回答by Duke Dougal

The actual solution to this problem is to approach it differently.

这个问题的实际解决方案是以不同的方式处理它。

Probably your goal is some sort of initialization which typically happens at the top level of an application.

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

The solution is to ensure that there is only ever one single JavaScript statement at the top level of your application. If you have only one statement at the top of your application, then you are free to use async/await at every other point everwhere (subject of course to normal syntax rules)

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

Put another way, wrap your entire top level in a function so that it is no longer the top level and that solves the question of how to run async/await at the top level of an application - you don't.

换句话说,将整个顶层包装在一个函数中,使其不再是顶层,这解决了如何在应用程序的顶层运行 async/await 的问题 - 你没有。

This is what the top level of your application should look like:

这是您的应用程序的顶层应该是这样的:

import {application} from './server'

application();

回答by Gershom

To give some further info on top of current answers:

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

The contents of a node.jsfile are currently concatenated, in a string-like way, to form a function body.

node.js文件的内容当前以类似字符串的方式连接起来,形成一个函数体。

For example if you have a file test.js:

例如,如果您有一个文件test.js

// Amazing test file!
console.log('Test!');

Then node.jswill secretly concatenate a function that looks like:

然后node.js将秘密连接一个如下所示的函数:

function(require, __dirname, ... a bunch more top-level properties) {
  // Amazing test file!
  console.log('test!');
}

The major thing to note, is that the resulting function is NOT an async function. So you cannot use the term awaitdirectly inside of it!

需要注意的主要事情是生成的函数不是异步函数。所以你不能await直接在它里面使用这个词!

But say you need to work with promises in this file, then there are two possible methods:

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

  1. Don't use awaitdirectlyinside the function
  2. Don't use await
  1. 不要await直接在函数内部使用
  2. 不要使用 await

Option 1 requires us to create a new scope (and THIS scope can be async, because we have control over it):

选项 1 要求我们创建一个新的作用域(这个作用域可以是async,因为我们可以控制它):

// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
  await new Promise(...);
  console.log('Test!');
})();

Option 2 requires us to use the object-oriented promise API (the less pretty but equally functional paradigm of working with promises)

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

I personally hope that, if it's workable, node.js will by default concatenate code into an asyncfunction. That would get rid of this headache.

我个人希望,如果可行,node.js 会默认将代码连接成一个async函数。这样头疼的问题就解决了。

回答by Ahmed Bouchefra

Top-level await is a feature of the upcoming EcmaScript standard. Currently, you can start using it with TypeScript 3.8 (in RC version at this time).

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

How to Install TypeScript 3.8

如何安装 TypeScript 3.8

You can start using TypeScript 3.8 by installing it from npmusing the following command:

您可以通过使用以下命令从 npm 安装 TypeScript 3.8来开始使用

$ npm install typescript@rc

At this time, you need to add the rctag to install the latest typescript 3.8 version.

这时候需要添加rc标签来安装最新的typescript 3.8版本。

回答by Peracek

Since main()runs asynchronously it returns a promise. You have to get the result in then()method. And because then()returns promise too, you have to call process.exit()to end the program.

由于main()异步运行,它返回一个承诺。你必须在then()方法中得到结果。并且因为也then()返回 promise,你必须调用process.exit()来结束程序。

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