简体   繁体   中英

How do I go "async all the way down" with Node Express?

I have many async functions in my system, so I need to go "async all the way down", which is to the point where the http.Server and express.Application app are created.

(This is unavoidable in an async system - there will be many async routines which are needed in constructors, which cannot be done, and so we need to use async factory functions instead, which lead to async creep all the way down to the entry point.)

But I'm not sure of the Node/TypeScript syntax to use to bootstrap the app.

My main entry point is 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
  }

}

Then I have a bootstrapping module Main.ts :

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

Which should be run:

node ./dist/Main.js

But I'm not sure what to use in the export line. I tried all these:

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*

The last line works based on a smoke test - but I'm not sure if that's the way to do it, and whether there's something down the line that may fail.

What is the canonical way to start an asynchronous node app?


UPDATE
Based on @JacobGillespie's answer, the Main.ts bootstrapping module is now:

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

In my case, System.ts has handlers for errors and unhandled promises, and does logging (otherwise use the "alternative" line). So the bootstrapping module just bootstraps the system.

async / await here are operating on promises, so you essentially want to "start" the promise by calling .then or .catch .

My go-to snippet for this is creating an async run or main function, then attaching error handling to the process, something like this:

async function run() {
  // run the app, you can await stuff in here
}

run().catch(err => {
  console.error(err.stack)
  process.exit(1)
})

In your case that would look like ( 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)
})

You don't need to export anything since this module file isn't being imported anywhere else (it's the entry file).

You can just call system.then() or system.catch() , but personally I like the async function run() pattern since you may need to coordinate more than one async thing in the future and this makes the code more explicit.

system.start().then() => {
    value => export default value
}

In my opinion, a better way would be: 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}

And then in Main.ts:

import {System} from "yourpath"

And then:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM