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.