0

So basically I have a web application that uses promise. Below is my code:

for(var key in data){               
    var promise = getDataFNLN(idOfReviewee);
    promise.then(function(returnedFnLn){
        count = count + +1;
        AllReviewee[count] = returnedFnLn;

        console.log("firsst");
        return getDataFNLN(idOfReviewer[count]);
    }).then(function(returnedFnLn){
        count1 = count1 + +1;
        AllReviewer[count1] = returnedFnLn;

        console.log("second");
    })
}

function getDataFNLN(idRev){
    return new Promise (function(resolve,reject){
        getDataToUsers = firebase.database().ref("users").child(idRev);
        getDataToUsers.once("value",function(snap){ 
            var fnLn =snap.val();
            var first = fnLn.firstname;
            var second = fnLn.lastname;
            forPromiseFnLn = first.concat(" ",second);

            resolve(forPromiseFnLn);    
        });
    });
}

Assuming that the data variable in the for loop has 4 data, so it will loop four times. And through promise the output of the console must be:

first
second
first
second
first
Second
First
Second

but instead it outputs like this:

first
first
first
first
Second
Second
Second
Second

krlzlx
  • 5,752
  • 14
  • 47
  • 55
juvy
  • 13
  • 6
  • 1
    The reason is because your for loop is not asynchronous. That is, it will execute the loop for each 4 elements and then will resolve the promises once they finish processing. There are numerous implementations of asynchronous for loop (check this link: https://stackoverflow.com/questions/4288759/asynchronous-for-cycle-in-javascript) – Jonathan Hamel Jan 15 '18 at 15:59
  • hi jonathan, can you update the code for me? you know for me to have insights? thank youu – juvy Jan 15 '18 at 16:01
  • hi jonathan, posted a code below. can you take a look? still getting the same output in consolde despite of using async loop – juvy Jan 15 '18 at 17:10
  • Would you mind marking my answer as "Best answer" :) – Jonathan Hamel Jan 22 '18 at 21:37

2 Answers2

0

You could iterate your function by passing an index and incrementing this counter in the last .then.

I seem to be missing where the key is used in your for loop. I am assuming this is the idOfReviewee.

function iterateData(data, index) {
    // Make sure to check here for data length to not get undefined vars.          
    var promise = getDataFNLN(data[index]);
    return promise.then(function(returnedFnLn){
        count = count + +1;
        AllReviewee[count] = returnedFnLn;

        console.log("firsst");
        return getDataFNLN(idOfReviewer[count]);
    }).then(function(returnedFnLn){
        count1 = count1 + +1;
        AllReviewer[count1] = returnedFnLn;

        console.log("second");

        // Continue the loop incrementing the index
        return iterateData(data, ++index)
    })
}

function getDataFNLN(idRev){
    return new Promise (function(resolve,reject){
        getDataToUsers = firebase.database().ref("users").child(idRev);
        getDataToUsers.once("value",function(snap){ 
            var fnLn =snap.val();
            var first = fnLn.firstname;
            var second = fnLn.lastname;
            forPromiseFnLn = first.concat(" ",second);

            resolve(forPromiseFnLn);    
        });
    });
}
Jonathan Hamel
  • 1,393
  • 13
  • 18
0

Maybe you could use https://github.com/LvChengbin/sequence for your case. This library can help you to run promises in sequence and also has other APIs for managing the sequence.

You can modify your code like this:

var steps = [];

for(var key in data){
    steps.push( function() {        
        var promise = getDataFNLN(idOfReviewee);
        promise.then(function(returnedFnLn){
            count = count + +1;
            AllReviewee[count] = returnedFnLn;

            console.log("firsst");
            return getDataFNLN(idOfReviewer[count]);
        }).then(function(returnedFnLn){
            count1 = count1 + +1;
            AllReviewer[count1] = returnedFnLn;

            console.log("second");
        });
        return promise;
    } );
}

Sequence.all( steps ).then( results => {
    // results is a result list of each step.
} ).catch( e => {
    // any one step in the sequence failed
} );

Even push all steps into the sequence.

var steps = [];

for(var key in data){
    steps.push( function() {
        return getDataFNLN( idOfReviewee );
    } );

    steps.push( function( result ) {        
        var returnedFnLn = result.value;

        count = count + +1;

        AllReviewee[count] = returnedFnLn;

        console.log("firsst");

        return getDataFNLN(idOfReviewer[count]);
    } );

    steps.push(function( result ){
        var returnedFnLn = result.value;
        count1 = count1 + +1;
        AllReviewer[count1] = returnedFnLn;    
        console.log("second");
    } );
}

Sequence.all( steps ).then( results => {
    // results is a result list of each step.
} );

If the steps would be changed after initialized, you can use new Sequence:

const sequence = new Sequence();

sequence.on( 'success', ( result, index, results ) => {
    // this would be executed while each step succeeded
} );

sequence.on( 'failed', ( result, index, results ) => {
    // this would be executed while each step failed.
} );

sequence.end( 'end', () => {
    // this function will execute after all steps finished.
} );

sequence.append( your step(s) here );

You can get more information from the documentation on Github.

LCB
  • 971
  • 9
  • 22