Как я могу продлить обещание $q в Angularjs с помощью .success и .error
Я написал этот маленький код в пользовательской службе в AngularJS.
В моем сервисе:
var deferred = $q.defer();
var promise = deferred.promise;
deferred.resolve('success');
deferred.reject('error');
/* Handle success and error */
promise.success = function(fn) {
promise.then(function(response) {
fn(response);
});
return promise;
};
promise.error = function(fn) {
promise.then(null, function(response) {
fn(response);
});
return promise;
};
В моем контроллере:
promiseService.myPromise()
.success(function(data){
$scope.success= data;
})
.error(function(data){
$scope.error = data;
});
Я справляюсь с успехом и ошибкой с обещанием (услуга $q). Мне нужен этот код во множестве других сервисов, поэтому я хотел бы напрямую распространить службу $q на обычную.
Итак, я хотел бы что-то подобное в моем сервисе:
var deferred = myPromiseService.$qCustom.defer();
var promise = deferred.promise;
deferred.resolve('success');
deferred.reject('error');
return promise;
Любая идея? Я нашел некоторое объяснение для расширения фильтра в Angularjs. Моя проблема заключается в том, чтобы найти хороший способ расширить все функциональные возможности $q и добавить мои настройки.
Я начинаю с чего-то подобного, он работает, чтобы обработать $q из коробки:
angular.module('myApp').service('myPromiseService', function($q){
$qCustom = $q;
});
Ответы
Ответ 1
Здесь было найдено полное решение, в котором остановился @jessegavin.
var myApp = angular.module("myApp", []);
myApp.config(function ($provide) {
$provide.decorator('$q', function ($delegate) {
var defer = $delegate.defer;
$delegate.defer = function () {
var deferred = defer();
deferred.promise.success = function (fn) {
deferred.promise.then(function(response) {
fn(response.data, response.status, response.headers);
});
return deferred.promise;
};
deferred.promise.error = function (fn) {
deferred.promise.then(null, function(response) {
fn(response.data, response.status, response.headers);
});
return deferred.promise;
};
return deferred;
};
return $delegate;
});
});
Ответ 2
Если вы хотите изменить поведение по умолчанию для того, что вводится angular, вы можете использовать метод decorator()
в службе $provide
.
var myApp = angular.module("myApp", []);
myApp.config(function ($provide) {
$provide.decorator("$q", function($delegate) {
// The $delegate argument here refers to the $q service.
$delegate.defer = function() {
alert("You just tried to call defer()!");
};
// Now, every time angular provides an instance of $q via
// injection, it will return your customized version of $q.
return $delegate;
});
});
См. пример выше в действии http://plnkr.co/edit/RuZF2cGkVHwlu7NIhxEZ?p=preview
Что касается модификации $q
для добавления функций успеха и ошибок, я не уверен в данный момент. Но я уверен, что именно здесь вы захотите это сделать.
Ответ 3
ИМХО, украшение @jessegavin $q не является совершенным, оно не должно возвращать обещание происхождения в успех и функцию ошибки. Он потеряет функцию сглаживания пирамиды обратного вызова.
И он не может разделить данные ответа на успех и функцию ошибки $httpPromise.
например
//can't do this..
somePromise.success(function(){
return $http.get(...)//another primise
}).success(function(data){
//data from $http.get..
})
Вот моя версия, она распознает ответ HTTP и вернет следующее обещание.
Сделайте свой собственный $q таким же, как $httpPromise
$provide.decorator('$q', function($delegate) {
function httpResponseWrapper(fn) {
return function(res) {
if (res.hasOwnProperty('data') && res.hasOwnProperty('status') && res.hasOwnProperty('headers') && res.hasOwnProperty('config') && res.hasOwnProperty('statusText')) {
return fn(res.data, res.status, res.headers, res.config, res.statusText);
} else {
return fn(res);
}
};
};
function decorator(promise) {
promise.success = function(fn) {
return decorator(promise.then(httpResponseWrapper(fn)));
};
promise.error = function(fn) {
return decorator(promise.then(null, httpResponseWrapper(fn)));
};
return promise;
};
var defer = $delegate.defer;
$delegate.defer = function() {
var deferred = defer();
decorator(deferred.promise);
return deferred;
};
return $delegate;
});