Reputation: 1255
I have this code in which I add users to the Firebase DB, and resolve
the Promise
when the user import is done. In the resolve, I include arrays which contain the users that were added. These arrays are populated when a single user is added. The code is below:
return new Promise((resolve, reject) => {
let usersAdded = [];
users.map((user, index) => {
db.ref('/users').push(user, err => {
if(!err) {
usersAdded.push(user)
console.log(`Array at iteration ${index}: ${usersAdded}`)
}
if(index == users.length-1){
resolve({status: true, usersAdded})
}
})
})
})
Console Output:
Array at iteration 0: [{name: nadir, email: [email protected], creditCard: true}]
Array at iteration 1: [{name: nadir, email: [email protected], creditCard: true}, {name: arslan, email: [email protected], creditCard: true}]
Array at iteration 2: [{name: nadir, email: [email protected], creditCard: true}, {name: arslan, email: [email protected], creditCard: true}, {name: farhan, email: [email protected], creditCard: true}]
Although when I see the response on .then(user)
, it returns an empty array (usersAdded
). Users get added in Firebase as well. Can anyone tell me what is the problem here?
Edit:
I was able to solve it, the problem was that the Promise was resolved before the db.ref.push triggered the callback, in that callback, I was populating the array, as it was an async operation.
Upvotes: 0
Views: 1581
Reputation: 21110
Like CertainPerformance said in the comments your code only works assuming the push callbacks get called in order. Since they are most likely asynchronous the order of the callback execution is not guaranteed. This means if the last push callback is called first you promise already resolves. For this reason you should use Promise.all() to wait until all the push callbacks are resolved then handle the results.
return Promise.all(users.map(user => {
return new Promise(resolve => db.ref('/users').push(user, resolve));
}))
.then(pushResults => { // all push callbacks are resolved
return pushResults
.map((error, index) => error ? null : users[index])
.filter(Boolean);
});
You might however want to call reject if none of the users successfully saved. This makes the code more complicated, but you can than use catch on the returned promise if no users where saved.
// return a resolved promise if the users array is empty
if (!users.length) return Promise.resolve(users);
// handle a non-empty users array
return Promise.all(users.map(user => {
return new Promise(resolve => db.ref('/users').push(user, resolve));
}))
.then(pushResults => {
// all users had errors
if (pushResults.every(Boolean))
return Promise.reject(pushResults);
// one or multiple users had no errors
return pushResults
.map((error, index) => error ? null : users[index])
.filter(Boolean);
});
Returning a value other than a promise inside a then function will simply be forwarded to the next then as if you returned Promise.resolve(value)
.
Upvotes: 1