使用angularjs的promise资源中的循环索引出错

时间:2017-01-24 19:58:19

标签: javascript angularjs angular-promise

我在angularjs中有这个代码,它为循环的每个索引向API发送一个http请求,问题是我想访问promise中的索引,但是这给了我错误的索引。

  avgCEN=CENa/CENc;  
  avgECE=ECEa/ECEc;  
  avgBINF=BINFa/BINFc;  

CONSOLE:

指数外承诺:0

指数外承诺:1

承诺内的索引:2

承诺内的索引:2

我想要这个:

指数外承诺:0

承诺内的索引:0

指数外承诺:1

承诺里面的索引:1

2 个答案:

答案 0 :(得分:1)

使用let statement代替var statement来声明索引:

//for (var index = 0; index < array.length; index++) {
for (let index = 0; index < array.length; index++) {
      console.log("index outside promise: "+index);
      var elements = array[index];      

      MyResource.save(elements).$promise.then(function(response){
          console.log("index inside promise: "+index);
          //In this part show me the error, because the index is wrong
          array[index].status = true;
       }, function failed(response){
          console.log(response);
       });
}

或者使用IIFE

for (var index = 0; index < array.length; index++) {
  //IIFE
  (function (index) {
      console.log("index outside promise: "+index);
      var elements = array[index];      

      MyResource.save(elements).$promise.then(function(response){
          console.log("index inside promise: "+index);
          //In this part show me the error, because the index is wrong
          array[index].status = true;
       }, function failed(response){
          console.log(response);
       });
  }(index));
}

因为index变量被声明为var,JavaScript编译器会创建一个closure,它共享对index变量的引用。引用包含的值在调用.then方法内的函数之前发生更改。

要在调用.then方法内的函数之前保留该值,请将其声明为带有let statement的块范围变量,或使用Immediately Invoked Function Expression (IIFE) idiom

答案 1 :(得分:0)

您可以尝试将API调用逻辑拆分为单独的函数:

function originalFunction() {
    for (var index = 0; index < array.length; index++) {
        var elements = array[index];      

        save(elements, index);
    }
}

function save(elements, index) {
    MyResource.save(elements).$promise.then(function(response){
        doSomething(index);
    }, function failed(response){
        console.log(response);
    });
}

上面的解决方案将使您可以在API成功处理程序中访问正确的索引。但是,您无法按指定方式打印字符串,因为API调用是异步操作,而for循环中的其他代码同步运行。这意味着当您在promise语句的“外部”打印时,在API调用完成之后才能打印相应的消息。但是,下一个“外部”语句不会等到上一次API调用完成后再进行下一次API调用。这就是为什么print语句不符合您指定的顺序。

如果你绝对必须按照你的描述打印出语句,那么你需要阻止后续的API调用发生,直到当前的API完成,这将使整个过程变慢。如果这是您想要做的,以下代码应该起作用:

function originalFunction(nextInd) {
    // default the id of the next call to 0
    nextInd = nextId || 0;

    // If the index is valid for the current array, call the API method
    if (nextInd >= 0 && nextInd < array.length) {
        console.log("index outside promise: "+nextInd );
        var elements = array[nextInd];
        save(elements, nextId);
    }
}

function save(elements, index) {
    MyResource.save(elements).$promise.then(function(response){
        console.log("index inside promise: "+index);
        doSomething(index);

        // kick off the API call for the next element in the array
        originalFunction(index++);
    }, function failed(response){
        console.log(response);

        // kick off the API call for the next element in the array
        originalFunction(index++);
    });
}

// You can still call the originalFunction without parameters to kick it off
originalFunction();