【问题标题】:Javascript for loop PromisesJavascript for循环承诺
【发布时间】:2015-12-18 13:13:09
【问题描述】:

我有一个这样的网址数组

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

我想遍历 url 并在循环内执行异步任务,并且在异步任务完成之前不继续下一项。我知道你可以通过承诺来做到这一点,但我遇到了一些麻烦。这是我所拥有的

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'];

我这样保存

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 之一放在一起?为什么会这样?

【问题讨论】:

  • 只是为了确保我理解...您想使用异步调用作为同步调用吗?异步的主要原因是允许在完成调用过程之前继续!
  • 您是否希望每个 URL 都单独执行并等到另一个 URL 的整个循环体完成后再开始下一次迭代?现在,正如所写,这将立即为每个 URL 创建一个 Promise,并且每个 URL 都将尽可能完成执行。
  • 即使您不能使用 jQuery,请参阅此链接中的答案以了解如何构建代码:stackoverflow.com/questions/20688803/… ...这是假设您想要执行异步调用项目列表,并在进入下一个循环项目之前完成异步调用
  • Promises 都是关于异步的——这是 99% 的人想要确保速度的东西——所以它们与我认为的你需要的相反
  • @RodrigoGomes 是的,因为在我阅读响应后,我保存到我的 Parse 数据库,我想等待,这是一项后台工作,所以我不担心速度

标签: javascript promise


【解决方案1】:

我为动画做了类似的事情。

var actions = [drawXXX, fadeOutYYY, drawXYZ];


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

【讨论】:

    【解决方案2】:

    您的代码会立即触发两个 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();
    

    【讨论】:

    • 我在答案中添加了一个例子。
    • 无处可去,这就是为什么我称它未经测试:)。感谢您的提示,我更新了代码以包含 xml 读取。
    • ...但是,我认为这个解决方案已经不够简单了,所以我会在我的回答中反映出来。
    • 您可以在阅读网址后查看有关保存的编辑吗?
    • 我现在看到了。重试可能最好在 saveLoc_async(res, nextLoc).then(function { retry(); });但是现在这个问题变得很复杂了。
    【解决方案3】:

    不确定我是否理解您对 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-11
      • 2015-05-05
      • 1970-01-01
      • 2016-12-02
      • 1970-01-01
      • 2023-03-17
      • 2020-05-14
      相关资源
      最近更新 更多