问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/62607868/nodejs-js-how-to-export-promise-value-in-a-module-not-the-function