【问题标题】:NodeJS, JS how to export Promise value in a module, not the function?NodeJS,JS如何在模块中导出Promise值,而不是函数?
【发布时间】:2020-10-17 19:55:35
【问题描述】:

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

作为示例代码 sn-p 我把它放在这里

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

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

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

【问题讨论】:

    标签: javascript node.js asynchronous export


    【解决方案1】:

    给你两个答案:

    使用 CommonJS (CJS)

    使用 CommonJS(您在该示例中使用的模块系统),最好的办法是导出 promise。这样,使用你的模块的代码就有了一种标准的方式来处理这个值可能还不可用的事实——消费承诺:

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

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

    function go() {
      return new Promise((resolve, reject) => {
        setTimeout(() => resolve("Success!"), 500);
      });
    }
    
    module.exports = {AS: undefined};
    go().then((x) => {
      module.exports.AS = x;
    });
    

    使用您的模块的模块将不得不处理这样一个事实,即它们会在一段时间内得到undefined。这是使用上述模块的代码:

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

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

    使用 JavaScript 模块 (ESM)

    如果您可以改用 JavaScript 模块(Node.js 在 v12 中支持它们在标志后面,而在 v13+ 中没有标志,请将 "type": "module" 放在您的 package.json 中),您还有第三种选择:@987654321 @。使用顶级await(在我写这篇文章时积极地添加到 JavaScript 引擎中),你可以让你的模块执行等待一个承诺解决。所以你会这样做:

    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`
    

    您可以根据需要合并这些行。对于默认导出

    export default await go();
    

    对于命名导出:

    export const AS = await go();
    

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

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

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

    【讨论】:

    • FWIW,我在我的新书 JavaScript: The New Toys 第 13 章和第 19 章中介绍了所有这些内容。如果您有兴趣,请参阅我的个人资料了解详细信息和链接。
    • 谢谢。显然第二个是更清晰的解决方案。
    • @TigranSahakyan - 很高兴!你是说顶级await?是的,这是一个很大的进步。 :-)
    • 老实说,这个问题来自我在使用 Pulumi 时遇到的问题。 Here 是。
    猜你喜欢
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 1970-01-01
    • 2017-10-30
    • 1970-01-01
    • 2022-10-13
    相关资源
    最近更新 更多