Angularjs for循环问题

时间:2015-06-22 02:00:52

标签: angularjs ionic-framework ionic

有一个for循环,在for循环内我调用了一个AJAX请求。我遇到的问题是,for循环在请求完成之前完成。

我希望for循环只有在所需的AJAX请求完成后才能继续进行下一次迭代。

PS-AJAX工作正常。我从服务器上获得了所需的信息。只需先完成for循环迭代,而无需等待AJAX​​请求成功函数启动。因此,当AJAX成功函数最终触发变量cid中的值时,由于它已被for循环的最后一次迭代覆盖,因此尚无定论。

我希望只有在执行AJAX成功函数后才能继续执行for循环。

代码:

if (window.cordova) {
    db = $cordovaSQLite.openDB("my.db"); //device
} else {
    db = window.openDatabase("my.db", '1', 'my', 1024 * 1024 * 100); // browser
}

var query = "SELECT * FROM order_product";
$cordovaSQLite.execute(db, query, []).then(function(res) {
    if (res.rows.length > 0) {
        for (var i = 0; i < res.rows.length; i++) {
            console.log(" foreach SELECTED shopcart-> " + res.rows.item(i).id);
            var cid = res.rows.item(i).coffee_id;
            $http.post("http://192.168.1.4/coffeepayWeb/public/index.php/getsugar", {
                cid: cID
            })
            .success(function(result) {
                console.log("success");

                if (cid == 6) {
                  //do something
                } else {
                  //do something else
                }
            });
        }
    }
}

2 个答案:

答案 0 :(得分:3)

如果需要迭代索引,使用for对于异步操作是不安全的,只使用它来存储所需的值以进行异步操作(在这种情况下为$http.post),它应该如下所示:

var items = [];

for (var i = 0; i < res.rows.length; i++) {
  var item = res.rows.item(i);
  items.push(item);
}

在考虑$http返回承诺后,您应该能够映射items

中的所有元素
var getsugarUrl = 'http://192.168.1.4/coffeepayWeb/public/index.php/getsugar';

// Map the values to obtain the promises on each $http operation, the allSettled method of the
// [Kriskowal Q library](https://github.com/kriskowal/q/wiki/API-Reference) will be simulated
// this is because when one of the http requests fail then the $q.all method break and reject with an error
var promises = items.map(function (item) {
    var cid = item.coffee_id;
    return $http.post(getsugarUrl, { cid: cid })
      .then(function (result) {

        // You can take advantage of this closure to handle the result of the request an the
        // cid property, store your modified result on the value property from the return

        return {
          state: 'fullfilled',
          value: {
            result: result,
            cid: cid
          } // your modified result
        };
      })

      // Handle when the http request fails
      .catch(function (err) {
        return {
          state: 'rejected',
          error: err
        };
      });
  });

最后处理使用$ q.all获得的结果(您需要注入$ q服务)

$q.all(promises)
  .then(function (responses) {
    // iterate over the results
    responses
      .filter(function(response) { // only fullfilled results
        return response.state == 'fullfilled'; 
      })
      .forEach(function (response) {
        if (response.value.cid == 6) {
          //do something with response.value.result
        } else {
          //do something else
        }
      });
  });

使用此解决方案,http请求无法按顺序解析,但您可以控制它们何时完成并且您将具有正确的值cid

查看有关JavaScript Promises的更多信息

答案 1 :(得分:1)

$http使用promises,这意味着您需要在承诺范例中考虑问题。

考虑一个递归选项,您传入一个cID数组,每个调用都会为数组中的第一个cID发送$http.post;如果调用成功,我们将继续递归使用较小的数组,直到不再剩下。

创造了一个承诺&amp;在第一次调用中返回,每次成功查询都会收到通知(允许您执行per-cID逻辑),最后在所有查询完成时解析(或者在任何查询失败时被拒绝)。

// This function is called without deferred;
// deferred is used on recursive calls inside the function
function doPost(url, cidList, deferred) {
  if (deferred === undefined) {
    deferred = $q.defer();
  }

  var cid = cidList[0];
  $http.post(url, {cid: cid})
  .success(function(result) {
     // query succeeded; notify the promise
     deferred.notify({cid: cid, result: result});

     if (cidList.length > 1) {
       // there are more items to process; make a recursive
       // call with cidList[1:end]
       doPost(url, cidList.slice(1), deferred);
     } else {
       // we're done; resolve the promise
       deferred.resolve();
     }
  })
  .error(function(message) {
    // there was an error; reject the promise
    deferred.reject({cid: cid, message: message});
  });

  return deferred.promise;
}

// build the list of cIDs to pass into doPost
var cidList = [];
for (var i = 0; i < res.rows.length; i++) {
  cidList.push(res.rows.item(i).coffee_id);
}

// start the queries
doPost("http://192.168.1.4/coffeepayWeb/public/index.php/getsugar", cidList)
.then(function() {
  // promise resolved
  console.log("All done!");
}, function(info) {
  // promise rejected
  console.log("Failed on cID " + info.cid + ": " + info.message);
}, function(info) {
  // promise being notified
  console.log("Just did cID " + info.cid + ": " + info.result);

  // your per-cid handler
  if (info.cid == 6) {
    // do something
  } else {
    // do something else
  }
});

更新

由于问题的动机更多地与变量范围(而不是顺序HTTP请求)有关,这就是您真正需要的:

// Build the CID list so that we can iterate it
var cidList = [];
for (var i = 0; i < res.rows.length; i++) {
  cidList.push(res.rows.item(i).coffee_id);
}

// Iterate the list & call $http.post
cidList.forEach(function(cid) {
  // your $http.post() logic; each call will have its own
  // cid thanks to closures
});

每次迭代都会拥有自己的cid,您可以在.success().error()处理程序中使用它,而不必担心它会被覆盖。与其他解决方案一样,请求不是顺序的,但您可能并不需要它们在首位。