简体   繁体   中英

Javascript for loop Promises

I have an array of urls like this

var urls = ["www.google.com", "www.yahoo.com"];

And I want to loop though the urls and perform an async task inside the loop and not move on to the next item until the async task has finished. I know you can do this with promises but I have having some trouble with it. Here what I have

var xmlReader = require('cloud/xmlreader.js');

function readResponse_async(xlmString) {
    var promise = new Parse.Promise();
    xmlReader.read(xlmString, function (err, res) {
        if(err) {
            promise.reject(err);
        } else {
            promise.resolve(res);
        }
    });
    return promise;
}

for (i = 0; i < urls.length; i++) {

    Parse.Cloud.httpRequest({
        url: unionUrls[i],
    }).then(function(httpResponse) {
            try {
//              console.log(httpResponse.text)
                return readResponse_async(httpResponse.text)
            } catch (e) {console.log(e)}

}

But right now it doesn't wait for the readResponse_async to finish, how can I have it wait for that?

Thanks

EDIT

After reading the response I make a save to my database and I have another array like this

var location = ['USA', 'England'];

And I make the save like this

function saveLoc_async(data, location) {
var i3, i4, i5, m,
            TestItem = Parse.Object.extend("TestItem"),//can be reused within the loops?
            promise = Parse.Promise.as();//resolved promise to start a long .then() chain
        for (i3 = 0; i3 < data.count(); i3++) {
             (function(testItem) {
                        testItem.set("item", data.at(i));
                        testItem.set("location", location);
                        //build the .then() chain
                        promise = promise.then(function() {
                            return testItem.save();
                        });
                    })(new TestItem());
//************************
//CALL  retry(); here?
//**************************

}

Because with your answer I have

function retry() {
if (urlsUnion.length > 0) {
    var nextUrl = urlsUnion.pop();
    //********** ADDED LINE
    var nextLoc = location.pop();

    Parse.Cloud.httpRequest({
        url: nextUrl,
    }).then(function(httpResponse) {
        xmlReader.read(httpResponse.text, function (err, res) {
            if(err) {
                // show an error
            } else {
                //********** ADDED LINE
                saveLoc_async(res, nextLoc);
                retry();
            }
        });
    });
}
}

SO where should retry(); go because right now with the save sometimes it puts the second location with one of the first items url? why would that happen?

I did something similar to this for an animation.

var actions = [drawXXX, fadeOutYYY, drawXYZ];


this.startAnimation = function () {
    actions.reduce(function (previousAction, nextAction) {
        return previousAction.then(nextAction)
    }, $.when());
}

Your code fires both urls immediately, and does not wait in-between.

What you would have to do is to remove the first url from the array and fire it. In the 'then' branch check if you still have url's in the array and repeat.

Like this (untested, edited to make the code clean again):

var xmlReader = require('cloud/xmlreader.js');

function readResponse_async(xlmString) {
    xmlReader.read(xlmString, function (err, res) {
        if(err) {
            // show an error
        } else {
            readFirstUrl();
        }
    });
}

function readFirstUrl() {
    if (urlsUnion.length == 0) {
        return;
    }
    var url = urlsUnion.pop();
    Parse.Cloud.httpRequest({
        url: url,
    }).then(function(httpResponse) {
        readResponse_async(httpResponse.text);
    });
}

readFirstUrl();

Not sure I understand your use of unionUrls array, but if you have your URL's in a urls array, I think this is pretty clean:

function getUrl(url) {
      return Parse.Cloud.httpRequest(url)
                  .then( function(httpResponse) {
                     return readResponse_async(httpResponse.text);
                  });
}

urls.reduce( function(prev, url) {
   return prev ? prev.then( function() { getUrl(url); }) : getUrl(url);
 }, null);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM