【问题标题】:How do I go "async all the way down" with Node Express?如何使用 Node Express“一直异步”?
【发布时间】:2019-07-02 10:17:27
【问题描述】:

我的系统中有很多异步函数,所以我需要“一直向下异步”,即创建 http.Serverexpress.Application 应用程序。

(这在异步系统中是不可避免的 - 构造函数中需要许多异步例程,这是无法完成的,因此我们需要使用异步工厂函数,这会导致异步蔓延所有一直到入口点。)

但我不确定用于引导应用程序的 Node/TypeScript 语法。

我的主要入口点是System.ts:

class default export System {

  public constructor() {
    // init Express.Application
    // init http.Server
    // init other parts of the system
  }

  public async start(): Promise<void> {
    // start the system asynchronously
    // start listening with http.Server
  }

}

然后我有一个引导模块Main.ts

import System from "./System"
const system = new System();
export default ???;                      // PROBLEM IS HERE

应该运行的:

node ./dist/Main.js

但我不确定在导出行中使用什么。我尝试了所有这些:

export default await system.start();     // doesn't compile (obviously)
export default system.start();           // doesn't seem right
export default system.start().then();    // this works *maybe*

最后一行基于冒烟测试工作 - 但我不确定这是否是这样做的方法,以及是否存在可能失败的问题。

启动异步节点应用的规范方法是什么?


更新
根据@JacobGillespie 的回答,Main.ts 引导模块现在是:

import System from "./System"
new System().start().then();
//new System().start().catch(e => console.error(e));  // alternative

在我的例子中,System.ts 有错误处理程序和未处理的承诺,并进行日志记录(否则使用“替代”行)。所以引导模块只是引导系统。

【问题讨论】:

    标签: node.js typescript express async-await


    【解决方案1】:

    async / await 这里是对 Promise 进行操作,所以你本质上是想通过调用 .then.catch 来“启动”这个 Promise。

    为此,我的首选 sn-p 是创建一个异步 runmain 函数,然后将错误处理附加到进程中,如下所示:

    async function run() {
      // run the app, you can await stuff in here
    }
    
    run().catch(err => {
      console.error(err.stack)
      process.exit(1)
    })
    

    在你的情况下,看起来像 (Main.ts):

    import System from "./System"
    
    async function run() {
      const system = new System()
      await system.start()
    }
    
    run().catch(err => {
      console.error(err.stack)
      process.exit(1)
    })
    

    你不需要导出任何东西,因为这个模块文件没有被导入到其他任何地方(它是入口文件)。

    您可以直接调用system.then()system.catch(),但我个人喜欢async function run() 模式,因为您将来可能需要协调多个异步事物,这使得代码更加明确。

    【讨论】:

    • 感谢雅各布!假设我所有的异步编排已经在我的 System 类中,以及错误处理,那么我可以将引导模块简化为 system.start().then(); 之类的东西吗?那是“安全的”吗?
    • 唯一的潜在问题是,如果在 system 中抛出一个未被捕获的错误,它将被视为未捕获的 Promise 异常。调用.catch() 启动与.then() 相同的promise,因此我将其更改为system.start().catch(err =&gt; { ... }),您可能希望记录错误并在该错误处理程序中使用错误代码退出进程。跨度>
    • 你确实提到了“以及错误处理”所以你是正确的 .then() 很好 如果你完全确定一切都得到了处理,但总是有“如果错误处理程序中有错误怎么办”的情况下,因此进行最终检查很好。
    • 是的,但我已经在System.ts 内有一个未捕获的 Promise 处理程序、其他错误处理和日志记录......这是“入口点”,我只需要启动/引导它.
    【解决方案2】:
    system.start().then() => {
        value => export default value
    }
    

    在我看来,更好的方法是: System.ts:

    function System():Promise<string>{
        //setup express and the server
        return new Promise((res,rej) => {
            //the server var is just the http server instance
            server.listen(8000,() => resolve("server created"));
        });
    }
    export {System}
    

    然后在 Main.ts 中:

    import {System} from "yourpath"
    

    然后:

    System().then(() => {
        //code runs when server is created
    }).catch(err => console.error(err));
    

    【讨论】:

    • 对我不起作用:[ts] An export assignment can only be used in a module.
    • 那么,您到底想导出什么?承诺解决的价值?承诺本身?我的意思是,你想导入什么脚本?如果您只想在服务器创建后运行代码,您可以只导出承诺,并在导入它的脚本中,使用 .then() 来执行您的代码,另外,我认为您不需要一个类,功能将是足够的
    • 我想从 shell 运行异步应用
    • 谢谢!对于那些喜欢函数式方法和承诺的人来说,这似乎是一个很好的方法。
    • 好吧,前段时间我做了一个名为 translucid 的快速库,它基本上为你做了这个(+一些其他常用代码),npmjs.com/package/translucid,它不是专业的,我只是做了它所以我不需要再次编写相同的代码:)
    猜你喜欢
    • 2020-04-01
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 2013-05-24
    • 2019-04-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    相关资源
    最近更新 更多