AngularJS - почему promises ($ q) с $http?

Я изучаю AngularJS после преобразования из jQuery в течение нескольких лет. И некоторые биты гораздо более интуитивно понятны. Некоторые не так много:).

Я пытаюсь использовать promises, особенно $q в использовании с $http, и, похоже, не слишком много информации об этих двух комбинированных, которые я могу найти.

Почему я должен использовать promises вместо обратного вызова успеха/ошибки? Оба они используют использование обратных вызовов в реальности, так почему же обещание считается лучше? Например. Я мог бы создать функцию get(...), как показано ниже:

function get(url, success, error) {
    success = success || function () {};
    error = error || function () {};

    $http.get(url)
        .success(function (data) {
            success(data);
        })
        .error(function (error) {
            error(error);
        });
}

get('http://myservice.com/JSON/',
    function () {
        // do something with data
    },
    function () {
        // display an error
    }
);

Что хорошо (?), потому что он дает мне полный контроль над тем, что происходит. Если я вызываю get(...), тогда я могу управлять любыми успехами/ошибками везде, где вызывается get.

Если я конвертирую это для использования promises, я получаю:

function get(url) {
    return $http.get(url)
        .then(function (data) {
            return data;
        },
        function (error) {
            return error;
        });
}

get('http://myservice.com/JSON/')
    .then(function (data) {
        // do something with data
    });
    // cannot handle my errors?

Что сгущается, я согласен; нам также не нужно явно беспокоиться об обратном вызове success/error, но я, похоже, потерял контроль над обратным вызовом моей ошибки для запуска - потому что я не могу настроить второй обратный вызов для обработки ошибки.

Это означает, что если я использую эту функцию в службе, которая может использоваться несколькими контроллерами, то я не могу обновить пользовательский интерфейс, чтобы предупредить пользователя об ошибке.

Я что-то упустил? Есть ли причина, почему promises является предпочтительным? Я не могу найти пример, почему.

Ответ 1

Обычно вы обрабатываете асинхронные задачи в Javascript с обратными вызовами;

$.get('path/to/data', function(data) {
  console.log(data);
});

Он отлично работает, но начинает усложняться, когда вы входите в то, что называется "callback hell";

$.get('path/to/data', function(data) {
  $.get('path/to/data2' + data, function(data2) {
    $.get('path/to/data3' + data2, function(data3) {
      manipulate(data, data2, data3);
    }, errorCb);
  }, errorCb);
}, errorCb);

Альтернатива работает с promises и отложенным объектом;

Deferreds - representing units of work
Promises - representing data from those Deferreds

Придерживаясь этой повестки дня, вы можете помочь вам в каждом экзистенциальном случае:

  • У вас есть регулярный вызов, которому необходимо получить данные с сервера, манипулировать им и вернуться в область
  • У вас есть несколько вызовов, каждый из которых зависит от ценного (стратегия cahin).
  • Вы хотите отправить несколько (параллельных) вызовов и обработать их успех в 1 блоке
  • Вы хотите, чтобы ваш код был создан (не разрешайте обрабатывать результаты на контроллерах)

Ваша задача проще всего обрабатывать с помощью $q и $http

function get(url) {
    var deferred = $q.defer();
    $http.get(url)
        .success(function (data) {
            deferred.resolve(data);
        })
        .error(function (error) {
            deferred.reject(error);
        });

    return deferred.promise;
 }

И вызов сервисной функции тот же

get('http://myservice.com/JSON/')
.then(function (data) {
    // do something with data
});
// cannot handle my errors?

Ответ 2

Вы можете обрабатывать ошибку следующим образом:

get('http://myservice.com/JSON/')
    .then(function (data) {
        // do something with data
    },
    function (error) {
        //do something with error
    });

Но, к сожалению, поскольку вы уже поймали ошибку, окончательная ошибка не будет запущена. У вас также будет такая же проблема с успехом.

Чтобы заставить вас работать, вам нужно использовать $q.

function get(url) {
    var deferred = $q.defer();

    $http.get(url)
        .success(function (data) {
            deferred.resolve(data);
        })
        .error(function (error) {
            deferred.reject(error);
        });

    return deferred.promise;
}

Также нет необходимости передавать функции успеха и ошибки, потому что вместо этого вы можете использовать promises.