NodeJS、JS如何导出模块中的Promise值,而不是函数?

Tig*_*yan 2 javascript asynchronous export node.js

假设我想在单个 JS 模块中导出一些通过调用某个异步函数获得的值。使导出等待结果/Promise 解决的机制是什么?

作为示例代码片段,我将其放在这里

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

let AS;
go().then((x) => {
  AS = x;
});
module.exports = AS;
Run Code Online (Sandbox Code Playgroud)

该函数可以发出任何 API 请求。我不想导出整个函数并在其他模块中调用它。

T.J*_*der 7

给你两个答案:

\n

使用 CommonJS (CJS)

\n

对于 CommonJS(您在该示例中使用的模块系统),最好的选择是导出承诺。这样,使用模块的代码就有一种标准方法来处理该值可能尚不可用的事实\xc2\xa0\xe2\x80\x94 消费承诺:

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

但如果您想导出该值,也可以,但这通常不是您的最佳方法。您可以通过导出对象然后更新其AS属性来做到这一点:

\n
function go() {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => resolve("Success!"), 500);\n  });\n}\n\nmodule.exports = {AS: undefined};\ngo().then((x) => {\n  module.exports.AS = x;\n});\n
Run Code Online (Sandbox Code Playgroud)\n

使用您的模块的模块必须处理这样一个事实:在一段时间内,它们将获得undefined. 这是使用上面模块的代码:

\n
const mod = require("./promise");\nconst timer = setInterval(() => {\n    const AS = mod.AS;\n    console.log("AS = " + AS);\n    if (AS) {\n        clearInterval(timer);\n    }\n}, 100);\n
Run Code Online (Sandbox Code Playgroud)\n

如果你运行它,你会看到AS = undefined~5 次,然后AS = Success!.

\n

使用 JavaScript 模块 (ESM)

\n

如果您可以改用 JavaScript 模块(Node.js 在 v12 中支持它们后面的标志,而在 v13+ 中没有标志,请放入"type": "module"您的package.json),您还有第三个选择:顶级await。通过顶层await(在我编写本文时主动添加到 JavaScript 引擎中),您可以让模块执行等待 Promise 解决。所以你会这样做:

\n
function go() {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => resolve("Success!"), 500);\n  });\n}\n\nconst AS = await go();\nexport default AS; // Or `export { AS };`, but your CJS code was effectively doing `export default`\n
Run Code Online (Sandbox Code Playgroud)\n

如果需要,您可以合并这些行。对于默认导出

\n
export default await go();\n
Run Code Online (Sandbox Code Playgroud)\n

对于命名导出:

\n
export const AS = await go();\n
Run Code Online (Sandbox Code Playgroud)\n

使用您的模块的模块不必知道该AS值来自异步源这一事实;在模块评估完成(承诺解决后)之前,它们不会被评估。他们只是像往常一样导入:

\n
import AS from "./promise.js"; // If it\'s the default export\nconsole.log("AS = " + AS);\n
Run Code Online (Sandbox Code Playgroud)\n

顶级await在 Node v13+ 中位于--harmony-top-level-await标志后面,并且很快就会进入浏览器。

\n