3

I know node.js run asynchronously, so outer functions execute earlier than the inner. But what is the way to access the notification array outside the for loop? I would like to access all the values in array at once, is this feasible?

var notification=[];

for(var j=0;j<6; j++)
{
     getNotification(response[j].sender_id,function(results)     // a function called
     {
         notification[j] =results;
         console.log(notification); // output: correct   
     });          
}
console.log(notification);       // output: [], need notification array values here
DisplayName
  • 3,093
  • 5
  • 35
  • 42
Tirthankar Kundu
  • 695
  • 3
  • 9
  • 19
  • What's the error you're experiencing? – Alfie Hanssen Aug 02 '13 at 13:23
  • You can't. At least not reliably, what you have is a race condition, that is guaranteed to be lost. You use them in the callback. You can however, keep the notification in a closure and use it in other functions once the callback is complete, to make it look like you're doing this. This is precisely what the callback is for. To run a series of operations, within the scope of some asynchronous operation. – MobA11y Aug 02 '13 at 13:26
  • Also, creating functions in a loop is a bad idea. You should define your callback outside of your for loop, and use it as an argument. – MobA11y Aug 02 '13 at 13:41

3 Answers3

1

EDIT: If you don't want to use third party libs, this is how to do this in your own code.

/* jshint node:true*/


function getNotifications(responses, callbackToMainProgramLogic) {
    'use strict';
    var results = [];

    function getNotificationAsync(response) {
        getNotification(response.sender_id, function (data) {
            results.push(data);

            if (responses.length) {
                getNotificationAsync(responses.pop());//If there are still responses, launch another async getNotification.
            } else {
                callbackToMainProgramLogic(results);//IF there aren't we're done, and we return to main program flow
            }
        });
    }

    getNotificationAsync(responses.pop());
}

getNotifications(someArrayOfResonses, function (dataFromNotifications) {
    console.log('The collected data: ' + JSON.stringify(dataFromNotifications, 0, 4));
});

If you absolutely must, you could do something ridiculous like this. Your logic in the loopUntilDatReceived would be waiting for array sizes, not waiting for a non-empty string, but the idea is similar, and you shouldn't be using this anyway! :)

var fileData = '';
fs.readFile('blah.js', function (err, data) { //Async operation, similar to your issue.
    'use strict';
    fileData = data;
    console.log('The Data: ' + data);
});

function loopUntilDataReceived() {
    'use strict';
    process.nextTick(function () {//A straight while loop would block the event loop, so we do this once per loop around the event loop.  
        if (fileData === '') {
            console.log('No Data Yet');
            loopUntilDataReceived();
        } else {
            console.log('Finally: ' + fileData);
        }
    });
}

loopUntilDataReceived();

Did I mention this is ridiculous? Honestly, this is an awful idea, but it may help you understand what is going on and how the Node event loop works, and why what you want is not possible. AND why the other posts about callbacks, and flow control libraries are the way to go.

MobA11y
  • 18,425
  • 3
  • 49
  • 76
0

Send a callback to the notification loop like this:

var notification=[];

getNotificationArray( function() {
  console.log(notification);
});

function getNotificationArray (callback)
{
  for(var j=0;j<6; j++)
  {
    getNotification(response[j].sender_id,function(results)     // a function called
    {
      notification[j] =results;
      console.log(notification); // output: correct   
    });          
  }
  callback();
}
frhd
  • 9,396
  • 5
  • 24
  • 41
  • Actually, sorry this won't work. I realized that your callback is in the wrong place. getNotification() is the async portion. So your callback() is poorly located, pluse there is iteration going on, so you need some logic for waiting for multiple iterations of getNotification. – MobA11y Aug 02 '13 at 13:52
  • Yes, now it dawns on me, too. – frhd Aug 02 '13 at 13:58
  • I updated my answer to include a non-third party lib function, similar to what you attempted. Check it out. – MobA11y Aug 02 '13 at 13:59
  • Yes, that's the right order. Nice solution, I wish I could up-vote. Starred for later. – frhd Aug 02 '13 at 14:08
0

First off, you're having a closure issue in your code (please see the details here)

Then, you simply can't have the array values just next to the loop, because the values are not ready at this point. You need to wait until all 6 of your getNotification calls get resolved. You can do that with the async library. Something like:

var notification = [];

function createRequest (index) {
    return function (callback) {
        getNotification(response[index].sender_id, function(results) {
            notification[index] = results;
            callback(results);
        });
    }
}

var requests = [];
for(var j=0;j<6; j++) {
    requests.push(createRequest(j));
}

async.parallel(requests, function (allResults) {
    // notifications array is ready at this point
    // the data should also be available in the allResults array
    console.log(notifications);
});
Community
  • 1
  • 1
amakhrov
  • 3,820
  • 1
  • 13
  • 12