Зачем возвращать обещание и данные при использовании $http в службе Angular?

Я часто вижу в Интернете учебные пособия и фрагменты информации о сервисах Angular, чтобы выполнять вызовы $http, которые возвращают как обещание $http, так и некоторые данные. Если промис возвращается контроллеру, какой смысл возвращать данные в сервис? Я даже не понимаю, куда он возвращается. Вот пример того, что я имею в виду:

 // Function of MyStuffService:
 function getStuff() {
    return $http.get('/api/stuff')
        .success(function(data) {
            // Why return data here? How could I even get this returned value?
            return data;
        })
        .error(function(data) {
            console.error(data);
        });
}

// Controller:
function getStuff() {
    MyStuffService.getStuff()
        .success(function(data) {
            $scope.stuff = data;
        })
}

Разве я не могу просто переписать свою сервисную функцию как:

 // Function of MyStuffService:
 function getStuff() {
    return $http.get('/api/stuff')
        .error(function(data) {
            console.error(data);
        });
}

И позволить контроллеру получить данные из возвращенного промиса? Мне кажется, я чего-то здесь не понимаю. Любая помощь приветствуется.


person Kevin Salvesen    schedule 26.02.2015    source источник
comment
Какие учебники и какие фрагменты вы имеете в виду? .. возвращать данные в обратном вызове успеха, безусловно, странно.   -  person Faris Zacina    schedule 26.02.2015
comment
Например, здесь. Там есть комментарий о вещах, которые работают только в старых версиях Angular, но я решил, что первая часть была в порядке. Так что я должен избегать этого шаблона? Было бы нормально делать только function getStuff() {return $http.get('/api/stuff');} в моем сервисе?   -  person Kevin Salvesen    schedule 26.02.2015
comment
Да.. я думаю, что это прекрасно.   -  person Faris Zacina    schedule 26.02.2015
comment
@Klodo: В этом ответе не используется success, он использует then, из которого вы действительно можете return. Следует признать, что функция идентификации не имеет особого смысла в качестве обратного вызова.   -  person Bergi    schedule 26.02.2015
comment
@Bergi: Понятно, спасибо. Я думаю, следует прочитать о различиях между успехом/ошибкой и затем. Я думал, что успех — это просто синтаксический сахар, чтобы иметь четыре параметра (data, status, headers, config) вместо только result. Спасибо за помощь.   -  person Kevin Salvesen    schedule 26.02.2015
comment
Задача проста. Держите контроллер тонким, и в вашем примере вы используете только один запрос $http. В то время как в проекте мы можем писать больше запросов $http. Таким образом, мы могли бы иметь один запрос $http на фабрике или в службе и вызывать его каждый раз, когда вам нужно, просто передавая переменные. Это сокращает время кодирования и делает контроллер тонким. Других плюсов не вижу.   -  person Alaksandar Jesus Gene    schedule 26.02.2015


Ответы (3)


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

.success просто передает исходное обещание $http.get. Возврат данных из .success ничего не делает.

Итак, если у вас есть:

 function getStuff() {
    return $http.get('/api/stuff')
        .success(function(data) {
            // do something with data. returning doesn't do anything
        })
        .error(function(data) {
            console.error(data);
        });
};

в контроллере вы бы сделали:

getStuff().then(function(response){
  $scope.data = response.data; // this is the data available from `$http.get`
}
person New Dev    schedule 26.02.2015
comment
Вы проверили, что success работает так же, как then? Я совершенно уверен в обратном - person Bergi; 26.02.2015
comment
Но успех не возвращает новое обещание, о чем свидетельствует тот факт, что после этого вы можете использовать связанный метод .error. - person Dylan Watt; 26.02.2015
comment
@ Берги, ах, правда ... Я пропустил это. Возврат из .success бессмысленен — он просто передает исходное обещание $http. Фиксированный. - person New Dev; 26.02.2015
comment
Я думаю, что в приведенном выше коде есть небольшая ошибка. Функция then должна иметь параметр result, а не data, поскольку он не эквивалентен параметру data функции success. - person Kevin Salvesen; 27.02.2015
comment
@Klodo, да - data - это объект ответа в .then. Фактические данные будут data.data. Я отредактирую, чтобы было понятно, спасибо за указание - person New Dev; 27.02.2015

Учебник, на который вы ссылаетесь, не возвращает данные в обработчике успеха, он возвращает result.data в обработчике then. Затем возвращается то, что генерирует новое связанное обещание. Это удаляет данные HTTP-запроса, которые обычно присутствуют в .then.

Зачем беспокоиться?

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

Заставив его всегда возвращать .then, вы убедитесь, что ваши сервисы достаточно абстрагированы.

person Dylan Watt    schedule 26.02.2015
comment
На самом деле настоящая причина использования then вместо success заключается в том, что он создает связанное обещание для возвращаемого значения обратного вызова, чего success не делает. - person Bergi; 26.02.2015
comment
Но нет смысла беспокоиться об этом, если вы согласны с использованием .success, поскольку исходное обещание, данное $http, имеет этот метод с данными ответа в качестве единственного аргумента. Первоначальный вопрос заключался в том, почему бы не использовать .success в своем контроллере. - person Dylan Watt; 26.02.2015
comment
Ах да, я имел в виду вызов success в MyStuffService.getStuff, а не в контроллере. - person Bergi; 26.02.2015
comment
Да, я пытался объяснить, почему вообще использование .success — не лучший выбор. Немного жаль, что эти удобные методы существуют, так как они сбивают с толку людей, когда они впервые пытаются изучить промисы, а .success и .error не являются его частью. - person Dylan Watt; 26.02.2015

Обычно вы делаете это, если вам нужно выполнить некоторую обработку перед отправкой данных в контроллер.

Но в данном случае согласен так как нет обработки данных, нет необходимости в разрешении промиса в сервисе.

В этом случае я бы просто переписал сервисный метод следующим образом:

function getStuff() {
   return $http.get('/api/stuff');
}

Если мне нужно выполнить некоторую обработку перед возвратом данных в контроллер, я обычно использую $q, как показано ниже.

function getStuff() {
    var defer = $q.defer();
    $http.get('/api/stuff')
        .then(function(data) {
            // some processing
            defer.resolve(processedData);
        }, function(error) {
            defer.reject(error);   
        });
        return defer.promise;
}
person Abhishek Jain    schedule 26.02.2015
comment
Вы действительно не должны этого делать. Возвращаемое значение $http.get уже обещано, так что просто используйте then! - person Bergi; 26.02.2015
comment
Извините, мой плохой ... Я скопировал и вставил код ОП и изменил его .... Согласен, я должен был изменить его на тогда ... - person Abhishek Jain; 26.02.2015
comment
Нет, я имею в виду, что вы должны использовать then вместо создания нового deferred! Пожалуйста, прочитайте пост, на который я указал. - person Bergi; 26.02.2015
comment
Ааа, понял. Я частично согласен с этим... Но если доступ к моему сервису осуществляется из нескольких мест и данные нуждаются в обработке перед использованием, я бы использовал этот шаблон или, возможно, httpInterceptor для преобразования моего ответа. Но, как я сказал в своем ответе, если обработка не требуется, я просто верну обещание. - person Abhishek Jain; 26.02.2015
comment
Нет, просто не используйте этот шаблон (никогда)! Если данные нуждаются в обработке, вы можете и должны использовать then. - person Bergi; 26.02.2015