Q:

Waiting on a long-running code block in a loop

So I'm trying to wrap my head around why my loop doesn't appear to be executing in the right order. This is the call made by the worker thread when it's done sorting out the values.
worker.on('message',function(data) {
                console.log(data)
                for (var i of data.entries) { 
                    console.log(i.Email) 
                    db.rota.checkUserHasShifts(i.Email,function(flag) {
                        if (flag) {
                            console.log('e', i.Email)
                             db.rota.getShiftsForUser(i.Email,function(err, shiftData) {
                                if (!shiftData) return
                                shiftData.Shifts = i.Shifts
                                shiftData.save(function(err) {
                                    if (err) throw err;
                                })
                            })
                        } else {
                            console.log('n', i.Email)
                            var newShift = new db.rota({Email:i.Email,Shifts:i.Shifts})
                            newShift.save(function (err){
                                if (err) throw err
                            });
                        }
                    })  
                };
                console.log("Spreadsheet processed")
            })

For a set of 20 entries, this will:

Print the 'data' object out, which has 20 {Email:"someemail",Shifts:{date:time}} objects in an array
Print each email out, in the right order
Then execute 20 lots of the db code on the last email in the list, giving me 20 lines of n lastemail@example.com in console and 20 identical entries in the database.

The intended behaviour is obviously to wait for each entry before moving on to the next, or at least to queue an entry for each email in the set.
How do I get the loop to wait and properly execute the db.rota.checkUserHasShifts method and callback on all the entries, not just the last one?

A:

You have to scope your i variable before calling checkUserHasShifts otherwise it will be called 20 times with the last i value in your loop.
foreach (var i in items){
 (function(i){ db.rota.checkUserHasShifts(i)..})(i);
}

to understand why, I found section 6 "Scope Revisited" of this excellent article very useful (although it is targeted at folks coming from a C# background):
https://mauricebutler.wordpress.com/tag/c-javascript/
Relevant quote:

JavaScript does not have "Block Scope" thus the for loop has not introduced new scope. This means that each time the element variable is accessed, the same memory location is updated

This SO question also demonstrates the effect very well: JavaScript closure inside loops – simple practical example

