JavaScript for循环中的Promises

4

我有一个像这样的url数组

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

我希望能够循环遍历URL并在循环内执行异步任务,直到异步任务完成后再继续下一个项目。我知道你可以使用Promise来实现这个,但我在它上面遇到了一些问题。以下是我的代码:

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)}

}

但是现在它不等待readResponse_async完成,我该怎么让它等待呢?

谢谢。

编辑

读取响应后,我会将其保存到我的数据库中,并且我有另一个类似以下内容的数组

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?
//**************************

}

因为您的回答,我已经...
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();
            }
        });
    });
}
}

目前,在保存时,retry();应该放在哪里?有时它会将第二个位置与第一个项目的URL之一混淆,这是为什么呢?


3
请确认我是否理解...你想使用异步调用来作为同步调用?异步调用的主要原因是在调用过程结束之前允许继续执行其他操作。 - Rodrigo Gomes
你想让每个URL都在隔离环境中执行,并等待另一个URL的整个循环体完成后再开始下一次迭代吗?目前,按照现有的写法,这将立即为每个URL创建一个Promise,并且每个URL将在其能够执行时完成执行。 - Oliver Kane
即使你无法使用 jQuery,也可以查看此链接中的答案以了解如何构建你的代码结构:https://dev59.com/F2Ij5IYBdhLWcg3wCxF0... 假设你想对一系列项目执行异步调用,并在进行下一个循环项之前完成异步调用。 - t1nr2y
1
承诺(Promises)与异步操作息息相关,这正是99%的人想要确保速度的内容。因此,它们是您不需要的东西,我认为相反的是更符合您的需求。 - Simon H
@RodrigoGomes 是的,因为在我读取响应后,我会将其保存到我的 Parse 数据库中,并且我想要等待,这是一个后台作业,所以我不担心速度。 - spen123
@spenf10,请看一下这个帖子。我会帮助你实现你的目标。https://dev59.com/3m435IYBdhLWcg3w1juV - Rodrigo Gomes
3个回答

2

我曾经为一部动画做过类似的事情。

var actions = [drawXXX, fadeOutYYY, drawXYZ];


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

1
你的代码立即触发两个URL,没有等待时间间隔。
你需要从数组中删除第一个URL并触发它。在“then”分支中检查数组中是否仍有URL,然后重复操作。
像这样(未经测试,已编辑以使代码干净):
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();

我在答案中添加了一个示例。 - Michael D
没有地方,这就是我称之为未经测试的原因 :)。谢谢你的提示,我更新了代码,包括xml读取。 - Michael D
然而,我认为这个解决方案已经不够简单了,所以我会在我的答案中反映出来。 - Michael D
请问您能否查看一下有关读取URL后保存的编辑内容? - spen123
我现在明白了。重试最好在saveLoc_async(res, nextLoc).then(function { retry(); });中完成,但问题现在变得非常复杂。 - Michael D
我知道这变得更加复杂了,尝试逐步解决它,那么应该在这行代码 return testItem.save(); 之后还是之前呢? - spen123

0
我不确定我理解你对于 `unionUrls` 数组的使用,但如果你把 URL 存储在一个名为 `urls` 的数组中,我认为以下代码相当简洁:
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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接