You need to enable JavaScript to run this app. 如何导出then()回调中的值?Node.js模块导出异步值返回空对象问题
优惠活动
大模型
产品
解决方案
定价
更多

如何导出then()回调中的值?Node.js模块导出异步值返回空对象问题

空对象问题的核心原因

Node.js 加载 CommonJS 模块时,会 同步执行完模块顶层的所有同步代码就立刻完成导出流程。
你原代码里的got()是异步HTTP请求,执行到这行时模块不会等待请求返回的then回调逻辑跑完,就直接把当时的初始导出对象(默认是空对象{})返回给require()的调用方。等后面异步请求拿到结果、在最后一个then回调里执行module.exports = out时,外部require拿到的模块引用早就定型,根本接收不到后续的赋值,自然打印出来是空对象。
另外原代码里引入的fs模块全程没有使用,属于冗余依赖可以直接删掉。

推荐解决方案

方案1:导出Promise本身,由调用方异步取值(最常用)

不要在模块内部强行把异步结果转成同步导出,直接把整个请求处理的Promise链作为模块的导出值,由调用方自行等待异步结果:
模块文件示例:

const got = require('got');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const vgmUrl = 'https://example.com/somehtml.html';

// 直接把整个请求处理的Promise作为导出内容
module.exports = got(vgmUrl).then(response => {
    const dom = new JSDOM(response.body);
    const textContent = dom.window.document.getElementById("__NEXT_DATA__").textContent;
    const JSONData = JSON.parse(textContent);
    return JSONData.props.pageProps.text.vaccinaties.data.kpi_total.tab_total_estimated.value;
});

引入模块时的写法:

// 拿到的导出值本身是一个Promise,不能直接打印,需要异步等待结果
const dataPromise = require('./module.js');

// 写法1:用then处理返回结果
dataPromise.then(out => {
    console.log(out);
});

// 写法2:用async/await等待结果
async function printData() {
    const out = await dataPromise;
    console.log(out);
}
printData();

方案2:固定导出对象引用,异步更新对象属性

如果希望外部拿到一个固定引用的模块对象,等异步数据加载完成后更新对象内容,就不要在异步回调里直接给module.exports赋新值,而是修改导出对象的属性:
模块文件示例:

const got = require('got');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const vgmUrl = 'https://example.com/somehtml.html';

// 初始化固定结构的导出对象
module.exports = {
    data: null,
    isLoaded: false,
    // 预留注册回调的方法,数据加载完成后自动触发通知
    onDataReady: (callback) => {
        if (module.exports.isLoaded) {
            callback(module.exports.data);
        } else {
            module.exports._readyCallback = callback;
        }
    }
};

got(vgmUrl).then(response => {
    const dom = new JSDOM(response.body);
    const textContent = dom.window.document.getElementById("__NEXT_DATA__").textContent;
    const JSONData = JSON.parse(textContent);
    const result = JSONData.props.pageProps.text.vaccinaties.data.kpi_total.tab_total_estimated.value;
    
    // 只修改导出对象的属性,不重新赋值module.exports本身
    module.exports.data = result;
    module.exports.isLoaded = true;
    // 触发预先注册的回调
    if (module.exports._readyCallback) {
        module.exports._readyCallback(result);
    }
});

引入模块时的写法:

const dataModule = require('./module.js');
// 注册数据加载完成的回调
dataModule.onDataReady(out => {
    console.log('拿到的目标数值:', out);
});
避坑提醒
  • 禁止在异步回调里直接执行module.exports = 新值:CommonJS模块加载逻辑中,require()拿到的是模块导出初始值的引用,后续在异步流程里把module.exports指向新的内容,外部引用还是原来的空对象,完全感知不到变化。
  • 不要试图在模块顶层同步等待HTTP请求的结果:这类网络请求本身是异步流程,强行同步阻塞会卡住Node.js的事件循环,导致整个服务失去响应。

内容的提问来源于stack exchange,提问作者Bastiaan Buitelaar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.06 08:06:02