拒绝AngularJS中带有多个参数(如$http)的承诺
Rejecting promises with multiple arguments (like $http) in AngularJS
$http
承诺的回调有多个参数:body、status、headers、config。
我想亲手创造类似的承诺,但不知道如何做到这一点。我想做的或多或少是:
myservice.action().then(function(status, message, config) {
// ...
});
我知道我可以将带有键的对象传递给回调,但希望有类似于$http
的约定。我观察了角度源,但要么没有完全理解,要么就是做不好。
你知道如何创建能够将多个参数传递给回调/errbacks的promise吗?
正如评论中所建议的,看看AngularJS的$q
实现。这些医生因…而臭名昭著。。。有时很难理解。
但无论如何,让我们尝试一个简短的例子。我在CoffeeScript中这样做,因为我更喜欢它,但如果你想的话,你应该能够在CoffeeScript.org上编译这个例子。
让我们实现一项服务:
app = angular.module 'my.custom.services', ['your.other.modules']
app.factory 'Service', ['$http' , '$q', (http, q) ->
# this is your deferred result
deferred = q.defer()
get: ->
deferred.promise
]
这个很简单。这只是一个服务,它将使用$q
和$http
,因为a)我们想要一些我们正在谈论的基于甜蜜承诺的东西,b)"$http"本身就是一个很好的例子,可以调用异步,但其结果无法立即获得。
这里有趣的部分是这里返回的对象的get
部分。请注意,该服务是作为factory
实现的,而不是作为service
实现的。有关差异,请参阅此处。我通常认为它是一个服务的"新奇"版本,在公开服务的API之前,我只需要为自己的逻辑留出一些额外的空间(这确实意味着不同的东西,但这是另一个故事
无论如何,get
在被调用时将返回延迟对象的promise
。promise
是一个对象,它公开了一个then
方法。当使用此服务时,您可能会将其注入如下:
app = angular.module 'my.custom.application', ['my.custom.services']
app.controller 'AppController', ['Service', (service)->
service.get() # then what?
]
正如我所提到的,get
只会回报一个承诺。与现实生活一样,承诺必须在某个地方得到解决。所以,让我们在服务中做到这一点——只要我们完成了承诺的任务,我们的承诺就会得到解决。这可以是通过AJAX调用URL,也可以是大计算(有人知道第117个斐波那契数是什么吗?)。
对于我们的例子,我们使用http调用,就像我们现在不使用的那样,无论它是否以及何时会返回给我们:
app.factory 'Service', ['$http' , '$q', (http, q) ->
# this is your deferred result
deferred = q.defer()
# this is where http is used, this is started immediately, but takes a while
http.get('some-resource.json').then (response) ->
# now 'response' is the whole successful response, it has a data object with the payload
if !someCondition
deferred.resolve response.data #we have what we wanted
else
deferred.reject {error: "Failed", additional: "foo", number: 2} #we ran into some error
get: ->
deferred.promise
]
基于someCondition
,如果我们愿意,我们可以故意让请求失败。如果你想自己尝试,你也可以像文档中那样使用timeout
。
现在发生了什么?好吧,我们还有那个控制器:
app.controller 'AppController', ['Service', (service)->
service.get().then(successCallback, errCallback)
]
正如我所解释的,promise
公开了一个具有签名then(success, error)
的then
方法,其中success
和error
是将我们解析的任何内容作为自变量的函数,例如:
app.controller 'AppController', ['Service', (service)->
successCallback = (data) ->
# we can work with the data from the earlier resolve here
scope.data = data
errCallback = (err) ->
# the error object, we got from the rejection
console.log err.error # => "Failed"
service.get().then(successCallback, errCallback)
]
如果您希望将多个值传递给回调,我建议您在解析/拒绝promise时传递一个对象。您还可以为promise执行命名回调,就像angular在其$http
实现中所做的那样:
app.factory 'Service', ['$http' , '$q', (http, q) ->
# this is your deferred result
deferred = q.defer()
# [...]
get: ->
promise = deferred.promise
promise.success = (fn) ->
promise.then (data) ->
fn(data.payload, data.status, {additional: 42})
return promise
promise.error = (fn) ->
promise.then null, (err) ->
fn(err)
return promise
return promise
]
实际上,您扩展了方法success
返回的promise,该方法将单个方法作为回调,等待promise得到解析,然后使用回调。如果你想的话,你可以对任何其他方法做同样的事情(有关提示,请参阅角度实现)
在你的控制器中,你可以这样使用它:
service.get().success (arg1, arg2, arg3) ->
# => arg1 is data.payload, arg2 is data.status, arg3 is the additional object
service.get().error (err) ->
# => err
这是最基本的,如果你愿意,你可以进行实验,我建议你尝试以下方法:
- 具有多个延期承诺的服务中的多个承诺
- 试试另一种推迟结果的方法,比如长时间计算
此外,作为奖励:
- 尝试将成功/错误回调隔离到服务的命名方法中
这个例子使用了Angular中的$q
实现,当然可以使用另一个实现来实现promise,比如这个,它是$q
的基础。
- Angular中的过滤和$http承诺
- $http中的Angular 1数据绑定承诺不起作用
- 如何同时使用节点承诺和 http
- 承诺中的成功回调不会发生$http
- angular服务中的$http承诺
- 同步解决HTTP延迟承诺
- AngularJS$http承诺异常不会冒泡
- 从工厂返回控制器$http承诺时未定义
- 角度$http承诺无法解决
- Angular JS$http承诺表现得像真正的$q承诺吗?
- Angularjs模拟一个返回$http承诺的函数
- AngularJS -拒绝了使用$routeProvider:resolve的$http承诺
- Angular的$http承诺和回调函数没有触发
- Angular HTTP承诺返回空
- Angular js的Http承诺在typescript中
- 如何在$q下传递多个$http承诺
- 为什么这个对象在angular http承诺对象中是$window ?
- $http承诺不更新作用域(ng-hide)
- 拒绝Angular的$http承诺
- Angularjs $http承诺时没有返回对象