2013-12-16 19 views
13

Tôi đang cố gắng sử dụng lời hứa AngularJS/sau đó với chức năng đệ quy. Nhưng chức năng sau đó không được gọi (không có lỗi nào, thành công, thông báo gọi lại được gọi).AngularJS, hứa với chức năng đệ quy

Đây là mã của tôi:

đệ quy chức năng

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

sau đó

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

Tôi nghĩ, sau đó có để có được là người đầu tiên thông báo-callback ít nhất. Nhưng không có gọi lại. Sau đó, không hoạt động với chức năng đệ quy?

+0

Bạn có thể cho chúng tôi jsfiddle không? – Manishearth

+1

Một điều tôi thấy là bạn không thể trả lại một cái gì đó từ một chức năng gọi lại. Vì vậy, trả về deferred.promise trong .success và .error thực sự không làm gì cả. Không phải nguyên nhân của vấn đề. – Narretz

+1

Xác định 'loadCount' ở đâu? Và 'thông báo 'không hoạt động như bạn nghĩ. Tôi có một vấn đề mở cho rằng trong repo góc -> https://github.com/angular/angular.js/issues/5277 – Rifat

Trả lời

21

EDIT - 2015/11/11 Có một cách sạch hơn nhiều nếu bạn không quan tâm đến thông báo:

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

}; 

Cũ câu trả lời có sẵn ở đây:

Bạn liên tục có thể vượt qua lời hứa tất cả các cách thức thông qua.

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, tôi nghĩ rằng bạn quên thực sự vượt qua 'trì hoãn' trong cuộc gọi đệ quy của bạn, nhưng đây là câu trả lời đúng. Vấn đề bạn gặp phải là bạn đang tạo một đối tượng 'deferred' mới mỗi khi bạn gọi phương thức, thay vì sử dụng cùng một đối tượng cho toàn bộ quá trình. Vì vậy, lần đầu tiên bạn gọi loadSection2, bạn sẽ bị hoãn lại, nhưng sự trì hoãn được giải quyết thực sự bị hoãn lại10. Việc chuyển qua trả chậm sẽ giúp ích hoặc bạn có thể tạo biến bên ngoài phương thức của mình và sử dụng đóng để truy cập nó. – Hylianpuffball

+0

Bạn hoàn toàn đúng, ý tôi là đã vượt qua, hãy trả lời chỉnh sửa. –

+0

@MathewBerg hãy giúp tôi hiểu lý do "trả lại lời hứa hoãn lại" từ khối "khác". Tôi đã chuẩn bị phiên bản q của ví dụ này trong khối khác mà tôi không trả về hoãn lại.promise; và nó hoạt động tốt. [liên kết] (https://gist.github.com/pulakb/94d9d1c96e77537c304e) –

0

Fauphi,

Đệ quy là hoàn toàn khả thi nhưng không phải là một "promisy" cách tiếp cận đặc biệt.

Cho rằng bạn đã hoãn/hứa hẹn có sẵn, bạn có thể tạo động một chuỗi .then(), mang lại lời hứa về mảng được điền.

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

chưa được kiểm tra

là gì newSectionArray tại được tạo ra một cách ẩn danh và truyền chuỗi .then() bất kể thành công/thất bại của cá nhân GET, nổi lên như arr trong xử lý thành công .Sau đó thức, nơi nó được chuyển đến addContent(). Điều này tránh sự cần thiết cho thành viên newSectionArray trong phạm vi bên ngoài.

Sắp xếp lại một chút, loadSection2 có thể được ẩn danh, giảm thêm số lượng thành viên được thêm vào phạm vi bên ngoài.

Nhu cầu có một thông báo rõ ràng biến mất như:

  • không còn là một bậc thầy hoãn để được thông báo
  • console.log(result); trong xử lý thành công GET cung cấp tất cả các thông báo cần thiết.
3

Tôi muốn tạo một giải pháp không vượt qua biến "trì hoãn" và mặc dù tôi không nói đó là cách tiếp cận tốt hơn, nó hoạt động và tôi đã học được từ nó (jsfiddle).

19/Aug/14 - Cập nhật mã thành phiên bản ngắn hơn nhiều bằng cách xóa việc tạo một lời hứa khác bằng f1(). Tôi hy vọng rằng nó là rõ ràng như thế nào nó liên quan đến câu hỏi ban đầu. Nếu nó không cho tôi biết trong một bình luận.

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; 
} 
Các vấn đề liên quan