Search code examples
angularjsnode.jsexpressshadowing

NodeJs - cant access updated value of array outside function scope


I'm new to node and I'm trying to fetch the twitter id of a group of users. The module accepts an array of screen names and iterates over it to get the userId and pushes them to an array. The problem is, I can't return that array. I can access it inside the scope of the function but I can't access it outside it. I read the answers to a similar questions here and here about variable shadowing and tried it but it doesn't work.

I'm pretty sure I'm doing a dumb mistake. Can you please look at the code and help me out here?


// extractIDs.js

var Twitter = require('twitter');
var client = new Twitter({
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token_key: process.env.TWITTER_TOKEN_KEY,
    access_token_secret: process.env.TWITTER_TOKEN_SECRET
});


exports.getIDs = function (screenNames) {
    var ids = ['something'];
    for (var i = 0; i < screenNames.length; i++) {
        client.get('users/show', {
            screen_name: screenNames[i],
            include_entities: false
        }, function (error, tweets, response) {
            ids.push(tweets.id); 
            console.log(ids) // works fine
        });

    } 
    return ids; //'something' gets returned instead of the populated ids

}

// server.js

app.post('/sendlist', bodyParser.urlencoded({
        'extended': 'true'
    }), function (req, res) {
        res.json(extractIDs.getIDs(req.body.screen_name));
    }

);

// controllers.js

.controller('testCtrl', ['$scope', '$http', function ($scope, $http) {
        $scope.printIt = function () {
            console.log('stuff from controller');
            $http({
                method: 'POST',
                url: '/sendlist',
                data: {
                    "screen_name": ['aminspeaks', 'nodejs']
                }

            }).then(function successCallback(response) {
                    console.log('Got This response from server-- ' + response.data); // "Got This response from server-- something"
                },
                function errorCallback(response) {
                    console.log('Shit went down bro');
                });
        };
        console.log('testCtrl is working');
            }])


Solution

  • Your problem isn't with scoping or shadowing.

    The problem is, that you don't wait for the response of the Twitter api. You only set the ids within a callback but immediately return the array which is returned before any of the callbacks finish.

    The proper way would be to populate an array of promises using some promise library like bluebird and wait for that. As a crude hack you can try adding some timeout but then you risk incomplete results.