Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
801 views
in Technique[技术] by (71.8m points)

javascript - NodeJS, JS how to export Promise value in a module, not the function?

Let's say I want to export in a single JS module some value which is obtained by calling some async function. What is the mechanism to make the export wait for the result/Promise to be resolved?

As an example code snippet I put this here

function go() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Success!"), 3000);
  });
}

let AS;
go().then((x) => {
  AS = x;
});
module.exports = AS;

This function could make any API request. I don't want to export the entire function and call it in other module.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Two answers for you:

With CommonJS (CJS)

With CommonJS (the module system you're using in that example), your best bet is to export the promise. That way, code using your module has a standard way to handle the fact that the value may not be available yet?— Consuming the promise:

require("./your-moudule")
.then(AS => {
    // ...use `AS` here...
})
.catch(error => {
    // ...handle the fact we didn't get it here...
});

But if you want to export the value instead, you can, it's just usually not your best approach. You'd do that by exporting an object and then updating its AS property:

function go() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Success!"), 500);
  });
}

module.exports = {AS: undefined};
go().then((x) => {
  module.exports.AS = x;
});

Modules using your module would have to deal with the fact that for a time, they'll be getting undefined. Here's code using the module above:

const mod = require("./promise");
const timer = setInterval(() => {
    const AS = mod.AS;
    console.log("AS = " + AS);
    if (AS) {
        clearInterval(timer);
    }
}, 100);

If you run that, you'll see AS = undefined ~5 times and then AS = Success!.

With JavaScript Modules (ESM)

If you can switch to using JavaScript modules instead (Node.js supports them behind a flag in v12 and without a flag in v13+, put "type": "module" in your package.json), you have a third option coming: top-level await. With top-level await (actively being added to JavaScript engines as I write this), you can make your module execution wait for a promise to settle. So you'd do this:

function go() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Success!"), 500);
  });
}

const AS = await go();
export default AS; // Or `export { AS };`, but your CJS code was effectively doing `export default`

You can combine those lines if you want. For a default export

export default await go();

For a named export:

export const AS = await go();

Modules using your module don't have to be aware of the fact that the AS value comes from an asynchronous source; they aren't evaluated until your module evaluation has finished (after the promise settles). They just import as usual:

import AS from "./promise.js"; // If it's the default export
console.log("AS = " + AS);

Top-level await is in Node v13+ behind the --harmony-top-level-await flag, and will shortly be making its way into browsers.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...