Search code examples
javascriptnode.jspromisees6-promise

Promise.all() resolves to give the same value for each promise


I am writing a module which has a function to return a promise using Promise.all() to send emails to several users. Stripping down the code, I was able to reproduce the problem to the following snippet:

var getPromise = function(data) {
    return new Promise((resolve, reject) => {
        console.log("After Calling:\t\t", data.user);
        setTimeout(function() {
                console.log("While Resolving:\t", data.user);
                return resolve(data);
            },
            Math.random() * 1000);
    });
}

var getAllPromises = function(users, options) {
    var promises = [];
    users.forEach(user => {
        var userSpecificOptions = options;
        // var userSpecificOptions = {};
        userSpecificOptions.user = user;
        promises.push(getPromise(userSpecificOptions));
    });
    return Promise.all(promises);
}

var userlist = ["help", "promises", "are", "tough"];
var commonoptions = {
    str: "something",
}

getAllPromises(userlist, commonoptions)
    .then(data => console.log("Data:\n", data))

This gives me the following output:

After Calling:       help
After Calling:       promises
After Calling:       are
After Calling:       tough
While Resolving:     tough
While Resolving:     tough
While Resolving:     tough
While Resolving:     tough
Data:
 [ { str: 'something', user: 'tough' },
  { str: 'something', user: 'tough' },
  { str: 'something', user: 'tough' },
  { str: 'something', user: 'tough' } ]

However, switching the declaration for userSpecificOptions:

        // var userSpecificOptions = options;
        var userSpecificOptions = {};

gets the correct result:

After Calling:       help
After Calling:       promises
After Calling:       are
After Calling:       tough
While Resolving:     help
While Resolving:     promises
While Resolving:     are
While Resolving:     tough
Data:
 [ { user: 'help' },
  { user: 'promises' },
  { user: 'are' },
  { user: 'tough' } ]

What could be the issue? I feel there might be something that I'm missing about how Promises work.


Solution

  • You make all userSpecificOptions instances refer to the same options object:

    var userSpecificOptions = options;
    

    So, when you assign to userSpecificOptions.user, you actually modify options.

    Instead, you should take a copy of options:

    var userSpecificOptions = Object.assign({}, options);
    

    Or using the object literal spread:

    var userSpecificOptions = {...options};
    

    Then any change to that particular userSpecificOptions object, will not affect options or any other variable.