Have a Question?

If you have any question you can ask below or enter what you are looking for!

Question Detial

Folks, I have the following for loop, inside of which I call vehicles.alertsVid function from another module, which returns a status for each vehicle. The results do arrive, but later, and do not get added properly.

What is the proper way to write this, so the main for loop does not race ahead, and temp.status gets written in time? :)

for (var i = vehiclesStuff.length - 1; i >= 0; i--) {
var temp = {};
temp.name = vehiclesStuff[i].nickname.S;
temp.plate = vehiclesStuff[i].plate.S;
temp.base = vehiclesStuff[i].base.S;
temp.vin = vehiclesStuff[i].vin.S;
temp.vid = vehiclesStuff[i].vid.S;

var myfunc = function(t,results,done){return function(){
    console.log ("ALERTS",results);
    t.status = results.toString();
    done();
}};

vehicles.alertsVid(temp.vid, myfunc(temp));

vehicleArray.push(temp);
};
callback()

Answers

Gordon Linoff

6:05pm 19th January 2014

for (var i = vehiclesStuff.length - 1; i >= 0; i--) {
    var temp = {}
    temp.name = vehiclesStuff[i].nickname.S;
    temp.plate = vehiclesStuff[i].plate.S;

    var myfunc=function(t,results,done){return function(){
        console.log ("ALERTS",results);
        t.status = results.toString();
        done();
    }};


    vehicles.alertsVid(temp.vid, myfunc(temp,results, done));

    vehicleArray.push(temp);
};

When you call the internal function, the variables are bound to the call stack AT THE MOMENT OF CALLING. Therefore the callback function will not "race ahead".

Note that the function returns a function itself, and hence the double nesting. One of my signatures. =)

Sven Marnach

7:28am 23rd May 2017

You should familiarize yourself with the concept of closures. Closures are a powerful way of capturing the context of any given evaluation/execution chain.

function callbackClosure(temp){
  return function(results, done){
    console.log ("ALERTS",results);
    temp.status = results.toString();
    done();
  };
}

for (var i = vehiclesStuff.length - 1; i >= 0; i--) {
  var temp = {};
  temp.name = vehiclesStuff[i].nickname.S;
  temp.plate = vehiclesStuff[i].plate.S;
  temp.base = vehiclesStuff[i].base.S;
  temp.vin = vehiclesStuff[i].vin.S;
  temp.vid = vehiclesStuff[i].vid.S;

  vehicles.alertsVid(temp.vid, callbackClosure(temp));

  vehicleArray.push(temp);
}

What this code is doing is it is creating a new context by returning a function that is scoped by the callbackClosure execution instance with a particular passed in object that will be kept in its unique scope until execution.

This is assuming that your vehicles.alertsVid executes and returns in its callBack a results object, as well as a done function.

Learn more about closures at this question: How do JavaScript closures work?

T.J. Crowder

9:45pm 19th January 2014

If you have control over the alertsVid function that is called from vehicles you may like to pass it the whole temp object and let it handle that instead of temp.vid (where does this property come from anyway?).

This way, you are passing the same object reference so that when it is finally processed, you are adding the status to the right temp (rightTemp). That way it can return the right temp as an argument in the callBack.

You are initializing a new object temp, and adding name and plate. I don't see vid as a property on temp?

Also if you want to wait until all of your temps are processed and with a status BEFORE you call your final callback you can use a counter to wait for it to fire. If you don't want to do this, just ignore those lines... (I've commented with "// callBack handling")

Also... fix those semicolons. :P

var numProcessed = 0; // callBack handling
var numToProcess = vehiclesStuff.length; // callBack handling

for (var i = vehiclesStuff.length - 1; i >= 0; i--) {
    var temp = {};
    temp.name = vehiclesStuff[i].nickname.S;
    temp.plate = vehiclesStuff[i].plate.S;

    vehicles.alertsVid(temp, function (rightTemp, results, done) {
        console.log ("ALERTS",results);
        rightTemp.status = results.toString();            
        done();
        processedTemp(); // callBack handling
    })

    vehicleArray.push(temp);
}

// callBack handling
function processedTemp(){
  numProcessed++;
  if(numProcessed === numToProcess) callBack();
}

your vehicles.alertsVid function would then look like:

vehicles.alertsVid = function(temp, callBack){
  ...
  callBack(temp, results, done); // using the same temp (object reference) that was passed in!!!
};

This is all assuming that you have control over the vehicles.alertsVid function.