node.jsasync-awaitnode-moduleses6-modulesecmascript-2021

Does top-level await have a timeout?


With top-level await accepted into ES2022, I wonder if it is save to assume that await import("./path/to/module") has no timeout at all. Here is what I’d like to do:

// src/commands/do-a.mjs

console.log("Doing a...");
await doSomethingThatTakesHours();
console.log("Done.");
// src/commands/do-b.mjs

console.log("Doing b...");
await doSomethingElseThatTakesDays();
console.log("Done.");
// src/commands/do-everything.mjs

await import("./do-a");
await import("./do-b");

And here is what I expect to see when running node src/commands/do-everything.mjs:

Doing a...
Done.
Doing b...
Done.

I could not find any mentions of top-level await timeout, but I wonder if what I’m trying to do is a misuse of the feature. In theory Node.js (or Deno) might throw an exception after reaching some predefined time cap (say, 30 seconds).

Here is how I’ve been approaching the same task before TLA:

// src/commands/do-a.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";

const doA = async () => {
  console.log("Doing a...");
  await doSomethingThatTakesHours();
  console.log("Done.");
}

export default doA;

autoStartCommandIfNeeded(doA, __filename);
// src/commands/do-b.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";

const doB = async () => {
  console.log("Doing b...");
  await doSomethingThatTakesDays();
  console.log("Done.");
}

export default doB;

autoStartCommandIfNeeded(doB, __filename);
// src/commands/do-everything.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";
import doA from "./do-a";
import doB from "./do-b";

const doEverything = () => {
  await doA();
  await doB();
}

export default doEverything;

autoStartCommandIfNeeded(doEverything, __filename);

autoStartCommandIfNeeded() executes the function if __filename matches require.main?.filename.


Solution

  • Answer: No, there is not a top-level timeout on an await.

    This feature is actually being used in Deno for a webserver for example:

    import { serve } from "https://deno.land/std@0.103.0/http/server.ts";
    
    const server = serve({ port: 8080 });
    console.log(`HTTP webserver running.  Access it at:  http://localhost:8080/`);
    
    console.log("A");
    
    for await (const request of server) {
      let bodyContent = "Your user-agent is:\n\n";
      bodyContent += request.headers.get("user-agent") || "Unknown";
    
      request.respond({ status: 200, body: bodyContent });
    }
    
    console.log("B");
    

    In this example, "A" gets printed in the console and "B" isn't until the webserver is shut down (which doesn't automatically happen).