Michael Fulton Michael Fulton - 11 months ago 46
Node.js Question

How can I manage Node.js async variable scope?

I have the following code for populating my test database. The goal is to save the parent document after each of the child documents to the parent can have a reference to them.

function saveRecipe(ingredients, directions, recipe, done) {
var ingredientSaveTasks = createSaveTasks(ingredients)
var directionSaveTasks = createSaveTasks(directions)

(callback) => { async.series(ingredientSaveTasks, callback) },
(callback) => { async.series(directionSaveTasks, callback) }
], (err, results) => {
recipe.ingredients = results[0] // The returned ids for each ingredient
recipe.directions = results[1] // The returned ids for each direction

function createSaveTasks(objs) {
var saveTasks = []
for (var i = 0; i < objs.length; i++) {
var saveTask = function (callback) {
var obj = Object.assign({}, objs[i])
obj.save((err, result) => {
callback(err, result._id)
return saveTasks

I've tried a few variations on this and I think it has to do with variable scope. However, I thought by deep copying my obj with var obj = Object.assign({}, objs[i]) would save a "real" copy of the object for later use inside the async function.

Depending on which of the many way I've tried to make this work I end up with one of the following errors:

TypeError: obj.save is not a function

TypeError: Cannot read property 'save' of undefined

I've seen some talk about using .bind() to control variable scope but I'm not sure how to use it in this case.


Bind return a new function and you can specify the context assigned to the function (the value that you obtain when call "this" keyword inside the function) and/or the arguments passed to the function. Bind(thisArg, ...arguments). So in your case:

var saveTask = function(callback){this.save(...)}.bind(obj[i])

With this you specify the context, so in that function your object will be accesible as this. Some examples:

(function a(){console.log(this)}).bind({key : 'value'})();

var a = function(){console.log(this)}.bind({key : 'value'});