0

The below code works in order like this

-->then 1 
-->then 2
-->then 3
-->then 3 ends
-->then 4
-->then 5
--> x
--> y
--> x
--> y
-->then 6

But I want it to be in order like this:

-->then 1 
-->then 2
-->then 3
--> x
--> y
--> x
--> y
-->then 3 ends
-->then 4
-->then 5
-->then 6

This is the code: The problem is in forEach. If I have once("value") stuff in forEach, I couldn't manage waiting the result of it then proceeding to "then 4"

   let massUpdate={};
let licenseLength=0;
let refOfferLength =admin.database().ref()...
refOfferLength.once("value")
    .then(lengthSnapshot=>{
        console.log(" then :1 ");
        //....
    }).then(snap=>{
    console.log(" then :2 ");
    let ref = admin.database().ref()....
    return ref.once("value");
}).then(ref=>{
    console.log(" then :3 ");
    ref.forEach(function(pSnapshot){
        let pId = pSnapshot.key;
        let pPath = pSnapshot.val();

        let refP = admin.database().ref().child("asd").child(event.params.userId).child(pPath).child(pId);
        refP.once("value").then(snap=>{
            console.log(" then :x ");
            //.....


            let path_license = "asd/" + event.params.userId+"/"+urunPath+"/"+urunId+"/license";
            let val_license = "open";
            //....

            massUpdate[path_license]=val_license;

        }).then(snap=>{console.log(" then :y ");});

    });
    console.log(" then :3 ends");


}).then(snap=>{// 
    console.log(" then :4 ");
    let pathOffersAndUsers = "kpss_offers_and_users/"+event.params.offerId+"/"+event.params.userId;
    let valOfferDetails = {"created_date": (moment().utcOffset(3).format("Y-MM-DD HH:mm:ss"))};
    massUpdate[pathOffersAndUsers]=valOfferDetails;

    return true;

}).then(snap=>{// 
    console.log(" then :5 ");

    let ref = admin.database().ref();
    return ref.update(massUpdate);

}).then(snap=>{
    console.log(" then :6 ");

    console.log(" Done : "+ event.params.userId + " : "+ event.params.offerId);


}).catch(function (error){console.log(" E : "+error+" : "+ event.params.userId + " : "+ event.params.offerId);});
meh met
  • 73
  • 1
  • 1
  • 3
  • Uh, [don't use `forEach` with promises](http://stackoverflow.com/a/37576787/1048572) (or otherwise)? – Bergi Mar 24 '17 at 05:39

1 Answers1

0

In a then callback you should return a promise when you want to delay the next then callback in the then chain until that promise resolves.

You do have promises in your forEach loop, but their return value is lost in oblivion. You can chain them and return the resulting promise with reduce:

return ref.reduce(function(prom, pSnapshot){ // return(!) a promise from reduce
    let pId = pSnapshot.key;
    let pPath = pSnapshot.val();

    let refP = admin.database().ref().child("asd").child(event.params.userId).child(pPath).child(pId);
    return prom.then(function () { // return(!) the promise, chained to the previous
        return refP.once("value");
    }).then(snap=>{ 
        console.log(" then :x ");
        //.....
        let path_license = "asd/" + event.params.userId+"/"+urunPath+"/"+urunId+"/license";
        let val_license = "open";
        //....
        massUpdate[path_license]=val_license;
    }).then(snap=>{console.log(" then :y ");});
}, Promise.resolve()) // start the promise chain with a resolved promise
.then(function () { // Chain one more `then` callback to report
    console.log(" then :3 ends");
});

Depending on whether your loop-promises have to wait for the previous one to resolve or not, you could also use Promise.all, which allows to create the promises all in parallel:

return Promise.all(ref.map(function(pSnapshot){ // pass an array of promises
    let pId = pSnapshot.key;
    let pPath = pSnapshot.val();

    let refP = admin.database().ref().child("asd").child(event.params.userId).child(pPath).child(pId);
    return refP.once("value").then(snap=>{ 
        console.log(" then :x ");
        //.....
        let path_license = "asd/" + event.params.userId+"/"+urunPath+"/"+urunId+"/license";
        let val_license = "open";
        //....
        massUpdate[path_license]=val_license;
    }).then(snap=>{console.log(" then :y ");});
}))
.then(function () { // Chain one more `then` callback to report
    console.log(" then :3 ends");
});

I just mentioned the relevant part of the code, but you could (and should) move the last then call one level up in the main chain.

trincot
  • 317,000
  • 35
  • 244
  • 286