Bạn có thể giải quyết một lời hứa angularjs trước khi bạn trả lại nó?


125

Tôi đang cố gắng viết một hàm trả về một lời hứa. Nhưng có những lúc thông tin yêu cầu có sẵn ngay lập tức. Tôi muốn thực hiện nó trong một lời hứa để người tiêu dùng không cần phải đưa ra quyết định.

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        return $http.get('/someUrl', {id:id});
    }
}

Và sử dụng nó như thế này:

somethingService.getSomething(5).then(function(thing) {
    alert(thing);
});

Vấn đề là cuộc gọi lại không thực hiện cho lời hứa đã được giải quyết trước. Đây có phải là một điều hợp pháp để làm? Có cách nào tốt hơn để xử lý tình huống này?


10
Một cách đơn giản hơn để viết lợi nhuận trong trường hợp đầu tiên là return $q.when(Cache[id]). Dù sao đi nữa, điều này sẽ hoạt động và gọi lại cuộc gọi mỗi lần vì bạn đang tạo ra những lời hứa mới mỗi lần.
musically_ut


1
Crud. Một giờ của cuộc đời tôi mất. Tôi đã thử điều này trong một bài kiểm tra đơn vị và lời hứa được thực hiện sau khi bài kiểm tra hoàn thành, và tôi đã không thấy nó. Vấn đề với bài kiểm tra của tôi và không phải là mã.
Craig Celeste

Hãy chắc chắn rằng bạn gọi $ scope. $ Apply () để đảm bảo mọi thứ được giải quyết ngay lập tức trong quá trình thử nghiệm.
dtabuenc

Tôi nghĩ httpbackend.flush chiếm tài khoản này nhưng $ q có thể không. Tôi không sử dụng phạm vi trong thử nghiệm này. Tôi đang thử nghiệm dịch vụ trực tiếp, nhưng dù sao tôi cũng đã làm cho nó hoạt động được.
Craig Celeste

Câu trả lời:


174

Câu trả lời ngắn: Có, bạn có thể giải quyết một lời hứa AngularJS trước khi bạn trả lại và nó sẽ hoạt động như bạn mong đợi.

Từ Plunkr của JB Nizet nhưng được tái cấu trúc để hoạt động trong bối cảnh của những gì ban đầu được yêu cầu (tức là một chức năng gọi dịch vụ) và thực sự trên trang web.

Bên trong dịch vụ ...

function getSomething(id) {
    // There will always be a promise so always declare it.
    var deferred = $q.defer();
    if (Cache[id]) {
        // Resolve the deferred $q object before returning the promise
        deferred.resolve(Cache[id]); 
        return deferred.promise;
    } 
    // else- not in cache 
    $http.get('/someUrl', {id:id}).success(function(data){
        // Store your data or what ever.... 
        // Then resolve
        deferred.resolve(data);               
    }).error(function(data, status, headers, config) {
        deferred.reject("Error: request returned status " + status); 
    });
    return deferred.promise;

}

Bên trong bộ điều khiển ....

somethingService.getSomething(5).then(    
    function(thing) {     // On success
        alert(thing);
    },
    function(message) {   // On failure
        alert(message);
    }
);

Tôi hi vọng nó giúp ích cho ai đó. Tôi đã không tìm thấy câu trả lời khác rất rõ ràng.


2
Tôi không thể mô tả bằng những từ mà tôi hạnh phúc, bạn đã tiết kiệm cho tôi rất nhiều thời gian h.coates!
vui vẻ

Trong trường hợp http GET không thành công, lời hứa trả lại không bị từ chối theo cách này.
lex82

5
Vì vậy, tl; dr cho bài đăng này là: Có, bạn có thể giải quyết một lời hứa trước khi trả lại và nó sẽ bị đoản mạch như dự định.
tia

1
Câu trả lời này cũng áp dụng cho Q của Kris Kowal mà lời hứa của Angular dựa trên.
Keith

Tôi đã thêm một ví dụ xử lý lỗi vào câu trả lời của bạn, tôi hy vọng điều đó ổn.
Simon East

98

Cách đơn giản trả lại lời hứa đã được giải quyết trước trong Angular 1.x

Đã giải quyết lời hứa:

return $q.when( someValue );    // angular 1.2+
return $q.resolve( someValue ); // angular 1.4+, alias to `when` to match ES6

Lời từ chối:

return $q.reject( someValue );

1
Không cần nhà máy đó, các chức năng trợ giúp này đã có sẵn:{resolved: $q.when, rejected: $q.reject}
Bergi

Này Bergi, cảm ơn bạn đã đóng góp có giá trị của bạn. Tôi đã chỉnh sửa câu trả lời của mình cho phù hợp.
Andrey Mikhaylov - lolmaus

2
Tôi nghĩ rằng câu trả lời này nên được chọn.
Morteza Tourani

@mortezaT Nếu được chọn, nó sẽ không mang lại cho tôi huy hiệu vàng. ;)
Andrey Mikhaylov - lolmaus

6

Đây là cách tôi thường làm nếu tôi thực sự muốn lưu trữ dữ liệu trong mảng hoặc đối tượng

app.factory('DataService', function($q, $http) {
  var cache = {};
  var service= {       
    getData: function(id, callback) {
      var deffered = $q.defer();
      if (cache[id]) {         
        deffered.resolve(cache[id])
      } else {            
        $http.get('data.json').then(function(res) {
          cache[id] = res.data;              
          deffered.resolve(cache[id])
        })
      }
      return deffered.promise.then(callback)
    }
  }

  return service

})

DEMO


0

Bạn đã quên khởi tạo phần tử Cache

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        Cache[id] = $http.get('/someUrl', {id:id});
        return Cache[id];
    }
}

Lấy làm tiếc. Đúng. Tôi đã cố gắng đơn giản hóa mã cho rõ ràng trong câu hỏi. Mặc dù vậy, nếu nó đi vào lời hứa đã được giải quyết trước, nó dường như không gọi lại cuộc gọi lại.
Craig Celeste

2
Tôi không nghĩ rằng nếu bạn giải quyết một lời hứa bằng một lời hứa, thì lời hứa bên trong sẽ bị san phẳng. Điều này sẽ tạo ra các Cachelời hứa thay vì các đối tượng dự định và kiểu trả về cho các trường hợp khi một đối tượng nằm trong Cache và khi nó không giống nhau. Điều này đúng hơn, tôi nghĩ:$http.get('/someUrl', {id: id}).then(function (response) { Cache[id] = response.data; return Cache[id]; });
musically_ut

0

Tôi thích sử dụng một nhà máy để lấy dữ liệu từ tài nguyên của mình.

.factory("SweetFactory", [ "$http", "$q", "$resource", function( $http, $q, $resource ) {
    return $resource("/sweet/app", {}, {
        "put": {
            method: "PUT",
            isArray: false
        },"get": {
            method: "GET",
            isArray: false
        }
    });
}]);

Sau đó trưng bày mô hình của tôi trong dịch vụ như thế này tại đây

 .service("SweetService",  [ "$q", "$filter",  "$log", "SweetFactory",
    function ($q, $filter, $log, SweetFactory) {

        var service = this;

        //Object that may be exposed by a controller if desired update using get and put methods provided
        service.stuff={
            //all kinds of stuff
        };

        service.listOfStuff = [
            {value:"", text:"Please Select"},
            {value:"stuff", text:"stuff"}];

        service.getStuff = function () {

            var deferred = $q.defer();

          var promise = SweetFactory.get().$promise.then(
                function (response) {
                    if (response.response.result.code !== "COOL_BABY") {
                        deferred.reject(response);
                    } else {
                        deferred.resolve(response);
                        console.log("stuff is got", service.alerts);
                        return deferred.promise;
                    }

                }
            ).catch(
                function (error) {
                    deferred.reject(error);
                    console.log("failed to get stuff");
                }
            );

            promise.then(function(response){
                //...do some stuff to sett your stuff maybe fancy it up
                service.stuff.formattedStuff = $filter('stuffFormatter')(service.stuff);

            });


            return service.stuff;
        };


        service.putStuff = function () {
            console.log("putting stuff eh", service.stuff);

            //maybe do stuff to your stuff

            AlertsFactory.put(service.stuff).$promise.then(function (response) {
                console.log("yep yep", response.response.code);
                service.getStuff();
            }).catch(function (errorData) {
                alert("Failed to update stuff" + errorData.response.code);
            });

        };

    }]);

Sau đó, bộ điều khiển của tôi có thể bao gồm nó và phơi bày nó hoặc thực hiện những gì nó rơi đúng trong bối cảnh của nó chỉ bằng cách tham chiếu Dịch vụ được tiêm.

Có vẻ làm việc ok. Nhưng tôi là người mới đến góc cạnh. * xử lý lỗi chủ yếu là bỏ qua cho rõ ràng


getStuffPhương pháp của bạn đang sử dụng
antipotype bị
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.