【问题标题】:AngularJS, promise with recursive functionAngularJS,具有递归功能的承诺
【发布时间】:2014-01-03 15:08:24
【问题描述】:

我正在尝试将 AngularJS 的 promise/then 与递归函数一起使用。但是没有调用 then 函数(没有调用错误、成功、通知回调)。

这是我的代码:

递归函数

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

我认为,那么至少必须获得第一个通知回调。但是没有回调。 那么是不是使用递归函数?

【问题讨论】:

  • 你能给我们一个jsfiddle吗?
  • 我看到的一件事是你不能从回调函数中返回一些东西。所以在 .success 和 .error 中返回 deferred.promise 实际上什么都不做。虽然不是问题的原因。
  • 'loadCount' 定义在哪里?而且,notify 不像你想象的那样工作。我在角度回购中有一个未解决的问题-> github.com/angular/angular.js/issues/5277
  • 嗯,有一个解决问题的答案,但现在它消失了。问题是,每次调用 loadSection2() 时都会初始化“延迟”。 @Rifat:通知对我有用。只要 promise 没有解决,notify-callback 就会被调用。

标签: javascript angularjs recursion promise


【解决方案1】:

编辑 - 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;
};

【讨论】:

  • Mathew,我想你忘了在递归调用中实际传递 deferred,但这是正确的答案。您遇到的问题是您每次调用该方法时都在创建一个新的 deferred 对象,而不是在整个过程中使用相同的对象。所以当你第一次调用 loadSection2 时,你会得到 deferred1,但被解决的 deferred 实际上是 deferred10。传递 deferred 会有所帮助,或者您可以在方法之外创建变量并使用闭包来访问它。
  • 你说的完全正确,我的意思是让它通过,答案已编辑。
  • @MathewBerg 请帮助我理解“else”块中“return deferred promise”的原因。我准备了这个例子的 q 版本,在 else 块中我没有返回 deferred.promise;它工作正常。 link
【解决方案2】:

法菲,

递归是完全可行的,但不是特别“有希望”的方法。

鉴于您有可用的延迟/承诺,您可以动态构建一个.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() 链传递,而不管单个 GET 的成功/失败,在最终的 .then 成功处理程序中以 arr 出现,并传递给 @987654326 @。这避免了在外部范围内需要成员 newSectionArray

稍微重新排列,loadSection2 可以匿名,进一步减少添加到外部范围的成员数量。

显式通知的需要消失了:

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

【讨论】:

    【解决方案3】:

    我想制定一个不传递“延迟”变量的解决方案,即使我不会说这是一种更好的方法,但它确实有效,我从中学到了一点 (jsfiddle)。

    19/Aug/14 - 通过删除 f1() 中另一个 Promise 的创建,将代码更新为更短的版本。我希望清楚它与原始问题的关系。如果没有在评论中告诉我。

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

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 2021-08-08
      • 2014-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多