简体   繁体   中英

module.exports returns an empty object

So,I have the following js files:

test_api.js:

var request = require("request")

//I actually have a url here.API call which returns JSON.
var url = "";

request({
    url: url,
    json: true
}, function (error, response, body) {

    if (!error && response.statusCode === 200) {
        module.exports = body;
        console.log(body) // Prints the json response

    }
});

test.js:

var api = require('./test_api.js');
console.log(api);

So,when I run node test.js I get:

console.log(body) // Prints the json response
console.log(api); //Prints an empty object

Any idea why I get an empty object back?

You cannot assign module.exports or assign to exports asynchronously. Instead, you should consider exporting a function that accepts a callback and performs the request (caching/reusing the result if needed).

When you call request() , you pass it a callback function. That callback function is called sometime in the future (that's an asynchronous callback). Meanwhile the rest of your module continues to execute and your module initialize completes with nothing assigned to module.exports yet.

So, when the caller does:

var api = require('./test_api.js');

The module has finished loading and nothing was assigned to module.exports yet so therefore, it is still an empty object and thus api contains only an empty object.

Then, sometime later, your request() operation finishes and calls its callback. You then assign something to module.exports , but it's too late. The module was already loading and the caller already grabbed the old module.exports before you replaced it.

All network I/O in node.js is asynchronous. This means that the completion callback is called some indeterminate time in the future and the rest of your Javascript continues to execute. The only place you can process asynchronous results is inside the completion callback or in some other function that is called from that callback. Or, you can use promises to do that type of work for you.


So, basically you can't return results that were retrieved with asynchronous operations from the loading of a module and you can't assign them to module.exports . So instead, the modern way to design this is to export either a promise or a function that returns a promise and then the caller can use .then() on the promise to get access to the results.

Here would be a modern way to implement what it looks like you're trying to do using a promise.

var request = require("request")

//I actually have a url here.API call which returns JSON.
var url = "";

function requestP(options) {
    return new Promise((resolve, reject) => {
        request(options, (error, response, body) => {
            if (error) {
                reject(error);
            } else if (response.statusCode !== 200) {
                reject(new Error(`Network request returned status code ${response.statusCode}`));
            } else {
                resolve(body);
            }
        });
    });
}

module.exports = requestP({url, json: true});

Then, the caller would use that like this:

let api = require('./test_api.js');
api.then(body => {
    // process body here
}).catch(err => {
    // process err here
});

For a more general discussion of returning asynchronous results, see How do I return the response from an asynchronous call?

test_api.js:

var request = require("request")

//I actually have a url here.API call which returns JSON.
var url = "";

module.exports = function (callback) {

    request({
        url: url,
        json: true
    }, function (error, response, body) {
        if (error) {
            callback(error, null);
        }
        if (!error && response.statusCode === 200) {
            console.log(body) // Prints the json response
            callback(null, body);
        }
    });
};

test.js:

var api = require('./test_api.js');
function callback(error, body) {
    if (error) {
        console.log(error);
    } else {
        console.log(body);
    }
}
api(callback);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM