javascriptnode.jsfile-structure

How to export a variable that has value assigned aysnchronoulsy from a module in javascript?


consider this,

let value = "";
value = DATABASE_CALL();

module.exports = value;

When I require the above module in an another module and try to access the variable 'value', it is an empty string. How can I make the module.exports wait until the above DB call is completed and the variable is assigned a value?


Solution

  • I assume value = DATABASE_CALL(); is a stand-in for asynchronous code. (If it were really synchronous as shown there, you'd just use it as the initializer value on value.)

    You have a few options for exporting a value that's only available asynchronously:

    1. Using ESM instead of CommonJS and using top-level await to prevent he module from finishing loading until the database operation is complete.

      export default await DATABASE_CALL();
      

      ...where DATABASE_CALL returns a promise. (If it doesn't already, you can wrap it.)

      Code using it won't have to await it, but the module won't finish loading until the DB op is complete, and won't load at all if the DB op fails.

      This is really only appropriate if the module cannot be used at all without that value.

    2. Exporting a promise of the value (whether you switch to ESM or keep using CommonJS):

      module.exports = DATABASE_CALL();
      

      ...where (again) DATABASE_CALL returns a promise.

      Code using it would have to await the promise (or use explicit .then/.catch).

    3. Using ESM instead of CommonJS and using a flag value to indicate "not ready yet" (null and undefined are useful for that) and updating the value when the database call is complete:

      export let value = null;
      // ...later when DATABASE_CALL is complete
      value = /*...the value from the DB...*/;
      

      ESM exports are live bindings, meaning that if the source module updates the variable, imports in other modules see the updated value.

      Note: You can only do this with named exports (value in the example), not default exports.

      Of course, that means the code using it has to allow for the possibility it's not loaded yet.

    4. Exporting a function that provides the value, and that handles telling the caller the value isn't available yet (implementation left to the reader).

    There are probably other choices.

    In cases where the module is worthless without the asynchronous information, I usually use #1. If not, I usually use #2.