Angular HttpPromise: `success`/`error`方法和`then`的参数之间的区别

179
根据 AngularJS 文档,调用 $http 返回一个包含标准的 then 方法和两个 http 特定方法(successerror)的Promise 对象。 then 方法接受两个参数:一个 success 回调和一个 error 回调,它们将使用响应对象调用。 successerror 方法各自接受一个参数 - 一个函数,该函数在请求成功或失败时调用。传递给这些函数的参数是传递给 then 方法的响应对象的解构表示形式。
除了在一种情况下解构了 response 对象外,我不明白以下两点之间的区别:
  • 作为 promise.then 参数传递的成功/错误回调
  • 作为 Promise 的 promise.success/promise.error 方法的参数传递的回调
这两种方式传递看起来完全相同的回调函数有什么区别?
6个回答

204

这里已经有一些不错的答案了。但是值得强调的是并行性的不同之处:

  • success() 返回原始的promise
  • then() 返回一个新的promise

区别在于then()驱动顺序操作,因为每次调用都返回一个新的promise。

$http.get(/*...*/).
  then(function seqFunc1(response){/*...*/}).
  then(function seqFunc2(response){/*...*/})
  1. $http.get()
  2. seqFunc1()
  3. seqFunc2()

success()可以驱动并行操作,因为处理程序链接在同一个承诺上。

$http(/*...*/).
  success(function parFunc1(data){/*...*/}).
  success(function parFunc2(data){/*...*/})
  1. $http.get()
  2. 并行执行 parFunc1()parFunc2()

3
注意,当then被执行后返回的新的promise响应会导致successerror方法消失。对于http错误响应(例如404),在http.then(ok, err).then(ok, err)中的第一个then将传递给err处理程序,但是后续的then将传递到ok处理程序。基本上,http.success().error().success().error() 是可链接的,但$q promises则完全不同,它们与承诺和序列处理具体相关(而不是与http请求处理有关)。我花了很多时间才理解这一点,直到我仔细研究了它。 - jimmont
1
@jimmont successÕÆīerrorõĖŹµś»PromiseńÜ䵣ŻÕĖĖAPI’╝īÕ«āõ╗¼Ķó½µĘ╗ÕŖĀÕł░$http()ńÜäĶ┐öÕø×ÕĆ╝õĖŖŃĆé - event_jr
感谢@event_jr,这对我很清晰,并在文档中提出。对我来说不够清晰的是,$q和$http解决了不同的问题,以及返回新的承诺与通过传递相同的承诺相同,正如您(非常有帮助)的答案所指出的那样。 - jimmont
1
“parallel” 是什么意思,因为 JS 是单线程的?你是指执行顺序是不确定的吗? - Derek
2
@ Derek 第二个 success 将在第一个执行后执行,但在任何从它返回的 promise 解决之前,而第二个 then 将等待。如果您没有返回 promises,则两者的行为相同。 - Tamlyn
显示剩余2条评论

157

NB 这个答案事实上是错误的;正如下面的一条评论所指出的那样,success()会返回原始Promise。 我不会改变; 请留给OP自行编辑。


这两者之间的主要区别在于.then()调用返回一个Promise(用从回调函数返回的值解决),而.success()是注册回调的更传统的方式,并且不返回Promise。

基于Promise的回调函数(.then())使得链式调用Promise变得容易(进行一次调用、解释结果,然后进行另一次调用、解释结果,再进行另一次调用等等)。

.success()方法是一种简化和方便的方法,当您不需要链接调用或使用Promise API时(例如在路由中)。

总之:

  • .then() - Promise API的全部功能,但略微冗长
  • .success() - 不返回Promise,但提供了稍微更方便的语法

45
另一个重要的区别是,then 回调只接受一个参数——响应结果;而 successerror 则将响应结果的各个组成部分——datastatusheaderconfig 作为单独的参数传递。 - Michelle Tilley
1
@BrandonTilley 完全正确,但问题的提问者已经解决了,所以我觉得没必要在这里重复。 - pkozlowski.opensource
45
虽然文档没有明确说明,但我们可以推断出.success()方法返回原始的 $http promise 对象,因为链式调用 $http(...).success(...).error(...) 是可行的。如果像看起来合理的那样,反向的 $http(...).error(...).success(...) 也是可能的,那么.error()应该也会返回原始的 promise 对象。.then() 的区别在于它返回一个 新的 promise 对象。 - Beetroot-Beetroot
3
来自angular.js的$http服务源代码:promise.success = function(fn) { promise.then(function(response) { fn(response.data, response.status, response.headers, config); }); return promise; }; - Alex Che
7
请注意,success已被弃用。从https://docs.angularjs.org/api/ng/service/$http#deprecation-notice中得知,“$http”的遗留承诺方法“success”和“error”已被弃用。请使用标准的“then”方法替代。如果将$httpProvider.useLegacyPromiseExtensions设置为false,则这些方法将抛出“$http/legacy”错误。 - Sam Barnum
显示剩余2条评论

114

一些简单的GET请求代码示例。也许这有助于理解它们之间的区别。 使用then

$http.get('/someURL').then(function(response) {
    var data = response.data,
        status = response.status,
        header = response.header,
        config = response.config;
    // success handler
}, function(response) {
    var data = response.data,
        status = response.status,
        header = response.header,
        config = response.config;
    // error handler
});

使用success/error

$http.get('/someURL').success(function(data, status, header, config) {
    // success handler
}).error(function(data, status, header, config) {
    // error handler
});

5
谢谢,但这个问题更多地涉及这些功能的区别或者它们存在的原因,如果它们执行相同的操作。从文档中可以理解如何使用它们的区别。 - ejoubaud
39
我个人喜欢简短的代码示例,这也是我在这里发布它们的原因。Angular文档有时会忽略简洁明了的示例。 - TheHippo
2
重要的是要強調第一個gist的回應物件包含了第二個gist的"data, status, header和config"。這意味著回應物件有一個額外的層級深度。 - geoom
将响应值传递到变量data、status、header、config是否比仅返回response有任何好处? - ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

27

.then()可链式调用并等待前一个.then()解决。

.success()和.error()可以链接,但它们会同时触发(所以没有太多意义)。

.success()和.error()仅适用于简单的调用(易制造者):

$http.post('/getUser').success(function(user){ 
   ... 
})

这样你就不必再输入这个了:

$http.post('getUser').then(function(response){
  var user = response.data;
})

但通常我使用.catch()来处理所有错误:

$http.get(...)
    .then(function(response){ 
      // successHandler
      // do some stuff
      return $http.get('/somethingelse') // get more data
    })
    .then(anotherSuccessHandler)
    .catch(errorHandler)
如果您需要支持<= IE8,则应像这样编写.catch()和.finally()(IE中的保留方法):
    .then(successHandler)
    ['catch'](errorHandler)

工作示例:

以下是我以更多的代码方式编写的内容,以便在处理错误等方面刷新我的记忆:

http://jsfiddle.net/nalberg/v95tekz2/


唯一的答案展示了“返回另一个Promise”的工作原理。 - zjk

17

仅为了完整性,这里有一个代码示例,指示差异:

成功 \ 错误:

$http.get('/someURL')
.success(function(data, status, header, config) {
    // success handler
})
.error(function(data, status, header, config) {
    // error handler
});

然后:

$http.get('/someURL')
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
})
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
})
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
}).

太好了!你有一个使用连接操作有用的例子吗? - geoom
4
"then" 方法的优点在于,你可以更容易地将异步操作依次写在一起,使得代码更加简洁易懂。 - MichaelLo

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接