Angular HttpPromise: разница между методами `success` /` error` и аргументами `then`


177

Согласно AngularJS doc , звонки, чтобы $httpвернуть следующее:

Возвращает объект обещания со стандартным методом then и двумя http-специфическими методами: success и error . Метод then принимает два аргумента: успех и обратный вызов ошибки, который будет вызван с объектом ответа. В успехе и ошибка метода принимает единственный аргумент - функцию , которая будет вызвана , когда запрос успешно или не соответственно. Аргументы, передаваемые в эти функции, представляют собой деструктурированное представление объекта ответа, переданного в метод then.

Помимо того факта, что responseобъект был разрушен в одном случае, я не понимаю разницу между

  • обратные вызовы об успехе / ошибке передаются в качестве аргументов promise.then
  • обратные вызовы, переданные в качестве аргументов для promise.success/ promise.errorметодов обещания

Есть ли? Какой смысл в этих двух разных способах передавать, казалось бы, идентичные обратные вызовы?

Ответы:


156

NB. Этот ответ фактически неверен; как указано в комментарии ниже, success () возвращает исходное обещание. Я не буду меняться; и оставьте это для OP для редактирования.


Основное различие между двумя заключается в том, что .then()вызов возвращает обещание (разрешается с помощью значения, возвращенного из обратного вызова), в то время .success()как более традиционный способ регистрации обратных вызовов и не возвращает обещание.

Обратные вызовы на основе обещаний ( .then()) облегчают цепочку обещаний (выполнить вызов, интерпретировать результаты, а затем выполнить другой вызов, интерпретировать результаты, сделать еще один вызов и т. Д.).

Этот .success()метод является упрощенным, удобным методом, когда вам не нужно ни связывать вызовы, ни работать с API обещаний (например, при маршрутизации).

Коротко:

  • .then() - полная сила обещающего API, но немного более многословная
  • .success() - не возвращает обещание, но предлагает несколько более удобный синтаксис

44
Еще одна большая разница в том , что thenобратные вызовы принимают единственный аргумент - ответ - в то время как successи errorпринимать отдельные компоненты реакции как arguments-- data, status, header, и config.
Мишель Тилли

1
@BrandonTilley совершенно верно, но автор вопроса уже понял это, поэтому я не чувствовал, что мне нужно повторять это здесь.
pkozlowski.opensource

45
Хотя в документации это не указано явно, мы можем сделать вывод, что .success()метод возвращает исходный объект обещания $ http, поскольку цепочка $http(...).success(...).error(...)возможна. Если, как представляется разумным, обратное $http(...).error(...).success(...)также возможно, тогда .error()также следует вернуть исходный объект обещания. Отличительная особенность .then()заключается в том, что он возвращает новое обещание.
Свекла-Свекла

2
Исходный код из angular.js службы $ http: promise.success = function(fn) { promise.then(function(response) { fn(response.data, response.status, response.headers, config); }); return promise; };
Alex Che

6
Обратите внимание, что successэто устарело. От docs.angularjs.org/api/ng/service/$http#deprecation-notice The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
Сэм Барнум,

204

Здесь уже есть несколько хороших ответов. Но стоит довести до ума разницу в предложенном параллелизме:

  • success() возвращает первоначальное обещание
  • then() возвращает новое обещание

Разница заключается в then()последовательных операциях, поскольку каждый вызов возвращает новое обещание.

$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достижении a, приводит к исчезновению методов successи error. Кроме того, для ответов об ошибках http (например, 404) первый thenвход http.then(ok, err).then(ok, err)будет передан errобработчику, а следующие будут переданы в okобработчик. По сути, они http.success().error().success().error()являются цепочечными, но обещания $ q весьма различны в том смысле, что все они связаны именно с обещанием и последовательностью обработки (а не обработкой http-запроса). Мне было трудно понять это, пока я не посмотрел внимательно.
Джиммонт

1
@jimmont successи errorне являются обычным API обещания, они привязаны к возвращаемому значению $ http ().
event_jr

Спасибо @event_jr, это ясно для меня и вызвано в документах. Что было не так ясно (для меня), так это то, как $ q и $ http решают различные проблемы, а также возвращают новые обещания по сравнению с прохождением того же самого - как указано в вашем (очень полезном) ответе.
Джиммонт

1
Что вы подразумеваете под параллелью, поскольку JS является однопоточным? Вы имеете в виду, что порядок выполнения недетерминирован?
Дерек

2
@Derek второй successбудет выполнен после того, как первый будет выполнен, но прежде, чем любое обещание, возвращенное из него, будет решено, тогда как второй thenбудет ждать. Если вы не отвечаете на обещания, тогда оба ведут себя одинаково.
Тамлин

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 Docs иногда пропускаются короткие точные примеры.
TheHippo

2
Важно подчеркнуть тот факт, что объект ответа первого списка содержит «данные, статус, заголовок и конфигурацию» второго списка. Это означает, что отвечающие объекты имеют один уровень глубины.
Geoom

Есть ли польза от передачи значений ответа переменным по data,status,header,configсравнению с простым возвратом response?
ʙᴀᴋᴇʀ ʙᴀᴋᴇʀ

27

.then () является цепным и будет ждать разрешения предыдущего .then ().

.success () и .error () могут быть объединены в цепочку, но все они будут срабатывать одновременно (так что особого смысла в этом нет)

.success () и .error () просто хороши для простых вызовов (easy makers):

$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/


Единственный ответ, который показывает, как работает «вернись, обещай»
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
Идея состоит в том, что подход «тогда» более полезен, так как вы можете легче писать асинхронные операции одну за другой.
MichaelLo

2

Официальное уведомление: успех и ошибка устарели, используйте вместо этого стандартный метод then.

Примечание об устаревании: Успешные и ошибочные методы обещания $ http устарели. Вместо этого используйте стандартный метод then. Если для $ httpProvider.useLegacyPromiseExtensions установлено значение false, то эти методы выдают ошибку $ http / legacy.

ссылка: https://code.angularjs.org/1.5.7/docs/api/ng/service/$http

скриншот: посмотреть скриншот

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.