您可以在返回之前解决angularjs承诺吗?


125

我正在尝试编写一个返回诺言的函数。但是有时候,所请求的信息会立即可用。我想将其包装在一个承诺中,这样消费者就不必做出决定了。

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

并像这样使用它:

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

问题在于,对于预解析的Promise不会执行回调。这是合法的事情吗?有没有更好的方法来处理这种情况?


10
在第一种情况下,更简单的写回报的方法是return $q.when(Cache[id])。无论如何,由于每次都创建新的Promise,所以每次都应该工作并调用回调。
musicly_ut 2013年


1
克鲁德。我的生命损失了一个小时。我在单元测试中进行了尝试,并且在测试完成后就实现了承诺,但是我没有看到它。我的测试有问题,而不是代码。
Craig Celeste 2013年

确保调用$ scope。$ apply()来确保在测试过程中一切立即解决。
dtabuenc 2013年

我认为httpbackend.flush解决了这个问题,但$ q可能没有。我在此测试中未使用范围。我正在直接测试服务,但是无论如何我都能正常工作。
Craig Celeste

Answers:


174

简短的答案:是的,您可以在返回AngularJS承诺之前先将其解析,并且其行为将达到您的期望。

来自JB Nizet的Plunkr,但经过重构后可以在最初要求的内容(即对服务的函数调用)的上下文中工作,并且可以在现场进行。

服务内部...

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;

}

控制器内部...

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

希望对您有所帮助。我没有找到其他答案很清楚。


2
我无法用言语形容我,您为我节省了这么多时间!
rilar 2014年

如果http GET失败,则不会以这种方式拒绝返回的诺言。
lex82 2014年

5
因此,该帖子的tl; dr是:是的,您可以在兑现承诺之前解决承诺,并且承诺会短路。
射线

1
该答案也适用于Angular的承诺所基于的Kris KowalQ。
基思2015年

我在您的答案中添加了一个错误处理示例,希望可以。
西蒙·伊斯特

98

如何简单地在Angular 1.x中返回预解析的Promise

解决的承诺:

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

拒绝承诺:

return $q.reject( someValue );

1
无需该工厂,那些辅助功能已经可用:{resolved: $q.when, rejected: $q.reject}
Bergi 2015年

嘿,贝尔吉,谢谢您的宝贵贡献。我已经相应地编辑了答案。
Andrey Mikhaylov-lolmaus 2015年

2
我认为应该选择这个答案。
Morteza Tourani

@mortezaT如果选择它,则不会给我颁发金色徽章。;)
安德烈·米哈伊洛夫

6

如果要在数组或对象中实际缓存数据,通常按照以下方法进行操作

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

您忘记初始化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];
    }
}

抱歉。确实如此。我试图简化代码以使问题更清楚。即使这样,如果它进入了预先解决的承诺中,它似乎也不会调用回调。
Craig Celeste 2013年

2
我不认为如果您用承诺解决承诺,内部承诺就不会变平。Cache如果对象在Cache中,而当对象不在Cache中时,这将用Promise而不是预期的对象填充,并且返回类型将不同。我认为,这是更正确的:$http.get('/someUrl', {id: id}).then(function (response) { Cache[id] = response.data; return Cache[id]; });
musicly_ut 2013年

0

我喜欢使用工厂从我的资源中获取数据,例如。

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

然后在这里在服务中公开我的模型

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

        };

    }]);

然后,我的控制器可以通过引用注入的Service来包含它并公开它,或者在它的上下文中正确执行它的操作。

似乎工作正常。但是我对棱角有点陌生。*为清楚起见,错误处理大多被忽略


你的getStuff方法是使用延迟反模式
BERGI
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.