2013-12-16 59 views
13

我想要使用AngularJS承诺/然后递归函数。但是没有调用then函数(调用错误,成功,通知回调函数都没有)。AngularJS,承诺与递归功能

这里是我的代码:

递归函数

loadSection2 = function() { 

    var apiURL = "http://..." 

    var deferred = $q.defer(); 

    $http({ 
     method: "GET", 
     url: apiURL 
    }).success(function(result, status, headers, config) { 
     console.log(result); 
     loadCount++; 
     if(loadCount < 10) { 
      newSectionArray.push(result); 
      loadSection2(); 
     } else { 
      loadCount = 0; 
      deferred.resolve(); 
      return deferred.promise; 
     } 
    }).error(function() { 
     return deferred.reject(); 
    }); 
    deferred.notify(); 
    return deferred.promise; 
}; 

然后

loadSection2().then(function() { 
    console.log("NEW SECTIONS LOADED, start adding to document"); 
    addContent(); 
}, function() { 
    console.log("ERROR CALLBACK"); 
}, function() { 
    console.log("NOTIFY CALLBACK"); 
}).then(function() { 
    loadScrollActive = false; 
}); 

我认为,当时有至少拿到第一通知回调。但没有回调。 然后不使用递归函数?

+0

你能给我们一个jsfiddle吗? – Manishearth

+1

我看到的一件事是你不能从回调函数中返回一些东西。所以在.success和.error中返回deferred.promise实际上什么都不做。虽然不是问题的原因。 – Narretz

+1

'loadCount'在哪里定义?而且,“通知”不像你想象的那样工作。我有一个开放的问题,在角度回购 - > https://github.com/angular/angular.js/issues/5277 – Rifat

回答

21

编辑 - 2015年11月11日有一个更清洁的方式,如果你不关心通知:

loadSection2 = function(){ 
    var apiURL = "http://..." 
    return $http.get(apiURL) 
     .then(function(response){ 
      loadCount++;   
      if (loadCount < 10) { 
       newSectionArray.push(response.data); 
       return loadSection2(); 
      } 
      loadCount = 0; 
     }); 

}; 

旧的答案可在这里:

你可以不断传递承诺一直贯穿始终。

loadSection2 = function(deferred) { 

    if(!deferred){ 
     deferred = $q.defer(); 
    } 
    var apiURL = "http://..." 

    $http({ 
     method: "GET", 
     url: apiURL 
    }).success(function(result, status, headers, config) { 
     console.log(result); 
     loadCount++; 
     if(loadCount < 10) { 
      newSectionArray.push(result); 
      loadSection2(deferred); 
     } else { 
      loadCount = 0; 
      deferred.resolve(); 
      return deferred.promise; 
     } 
    }).error(function() { 
     return deferred.reject(); 
    }); 
    deferred.notify(); 
    return deferred.promise; 
}; 
+1

Mathew,我想你忘了在递归调用中实际传递'deferred',但这是正确的答案。你遇到的问题是,每次调用方法时都会创建一个新的“延迟”对象,而不是在整个过程中使用同一个对象。所以当你第一次调用loadSection2时,你会得到deferred1,但延迟得到解决的实际上是deferred10。传递延迟会有所帮助,或者您可以在方法外部创建变量并使用闭包来访问它。 – Hylianpuffball

+0

你是完全正确的,我打算让它通过,编辑回答。 –

+0

@MathewBerg请帮我理解“返回延期承诺”从“其他”块的原因。 我已经准备了这个例子的q版本,其中在else块中我没有返回deferred.promise;它工作正常。 [链接](https://gist.github.com/pulakb/94d9d1c96e77537c304e) –

0

Fauphi,

递归是完全可行的,但不是一个特别 “promisy” 的做法。

鉴于您有延期/承诺可用,您可以动态构建一个.then()链,它提供了一个填充数组的承诺。

function loadSection2(arr) { 
    return $http({ 
     method: "GET", 
     url: "http://..." 
    }).then(function(result, status, headers, config) { 
     console.log(result); 
     arr.push(result); 
     return arr;//make the array available to the next call to loadSection2(). 
    }, function() { 
     console.log("GET error"); 
     return $q.defer().resolve(arr).promise;//allow the chain to continue, despite the error. 
     //or I think $q's .then() allows the much simpler form ... 
     //return arr; //allow the chain to continue, despite the error. 
    }); 
}; 

var newSectionPromise = $q.defer().resolve([]).promise;//note that the deferred is resolved with an anonymous new array. 
//Now we build a .then() chain, ten long, ... 
for (var i=0; i<10; i++) { 
    newSectionPromise = newSectionPromise.then(loadSection2); 
} 
// ... and do something with the populated array when the GETs have done their thing. 
newSectionPromise().then(function(arr) { 
    console.log(arr.length + " new sections loaded, start adding to document"); 
    addContent(arr); 
}, function() { 
    console.log("ERROR CALLBACK"); 
}).then(function() { 
    loadScrollActive = false; 
}); 

未经检验

什么newSectionArray现在是匿名的创建和不管成功的传下来的.then()链/个人的失败入眼,逐渐成为arr在最后。那么成功的处理程序,在那里传递给addContent()。这避免了在外部范围内需要成员newSectionArray

轻微重新排列,loadSection2可以匿名,进一步减少添加到外部作用域的成员数量。

需要有一个明确的通知消失为:

  • 不再有推迟的GET成功处理程序通知
  • console.log(result);主提供了所有必要的通知。
3

我想使未通过“延期”变量周围,即使我不会说这是一个更好的方法,它的工作原理,我学到了从它(jsfiddle)的解决方案。

19/Aug/14 - 通过删除在f1()中创建的另一个承诺,将代码更新为更短的版本。我希望能明确它与原始问题的关系。如果在评论中不让我知道。

f1().then(function() { 
    console.log("done"); 
}); 

function f1(counter) { 

    if (!counter) { 
     counter = 0; 
    } 

    counter++; 
    console.log(counter); 

    return asyncFunc().then(function() { 
     if (counter < 10) { 
      return f1(counter); 
     } else { 
      return; 
     } 
    }); 

} 

function asyncFunc() { 
    var deferred = $q.defer(); 

    $timeout(function() { 
     deferred.resolve(); 
    }, 100); 

    return deferred.promise; 
}