При создании сервисного уровня в приложении Angular я заметил много повторений кода для создания обещаний, поэтому попытался создать общий сервис getPromise, поскольку 90% обещаний имеют одинаковую структуру.

Хотя при возврате обещания из службы функция не выполняется как обычно, хотя возвращаемый объект тот же.

Кто-нибудь пробовал это делать? Например.

angular.module('fooApp')
.service('promise', function promise($q, $http) {
    return {
        getPromise: function (url, data) {

            var deferred = $q.defer();

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

            return deferred.promise;
        }
    };
})

.service('foo', function foo(config, promise) {
    return {
        getFoo: function (userId) {
            var deferred = $q.defer();
            var url = config.svcUser + 'GetFoo';
            var data {
                userId: userId
            };

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

            return deferred.promise;
        },
        getFoo2: function (userId) {
            var url = config.svcUser + 'GetFoo';
            var data {
                userId: userId
            };
            return promise.getPromise(url, data);
        }
   }
})


.controller('AgenciesCtrl', function ($scope, agency) {

    agency.getFoo().then(function (agencies) {
        // does fire
    });

    agency.getFoo2().then(function (foo) {
        // does not fire
    });

    $scope.loadAgency = function (agencyId) {
        agency.getFullAgencyProfile(agencyId).then(function (agency) {
            $scope.agency = agency;
        });
    }

});

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

0
JamesEddyEdwards 12 Ноя 2014 в 00:21
1
Я вижу это все время, например, @MaxFichtelmann сказал, что $http.post возвращает обещание, не нужно оборачивать его $q. Я не уверен, почему люди этого не понимают. Также хорошая идея с сервисом обернуть код X промисом, но вы уже можете сделать это с помощью $q.when(...) = Оборачивает объект, который может быть значением или (сторонним) тогда-способным промисом, в $ д обещание
 – 
m.e.conroy
12 Ноя 2014 в 00:39
Я думаю (и именно поэтому я удалил свой первоначальный комментарий), что причина в том, чтобы сгладить ответ и отбросить информацию о статусе и заголовках. Но думать об этом еще раз кажется плохой идеей, потому что отбрасывание статуса ошибок может быстро стать огромной проблемой.
 – 
Max Fichtelmann
12 Ноя 2014 в 00:46

2 ответа

Ты прав! Ваш код повторяется - это называется < strong>отложенный антишаблон.

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

Обещания Angular, поскольку обещания A+ предлагают довольно современную реализацию, и все, что Angular делает асинхронно, логически представляет собой однократную операцию уже возвращает обещание. Сюда входит все, что делает $http, а также $timeout, $resource и так далее.

Ваш код мог бы быть намного проще:

angular.module('fooApp')    
.service('foo', function foo(config, promise) {
    return {
        getFoo: function (userId) {
            var url = config.svcUser + 'GetFoo';
            var data { userId: userId };
            return $http.post(url, data).then(function(resp){
                 // any validations you need on the response go here
                 return response.data;
            });
        }
   }
}).controller('AgenciesCtrl', function ($scope, foo) {
    foo.getFoo().then(function (agencies) {
        // does fire, and schedules a digest because it's an Angular promise
        $scope.someVar = agencies; // safe to do here, since a digest will happen
    }); 
});
0
Community 23 Май 2017 в 14:57
Спасибо, Бен, мне действительно удалось добраться до этого момента после более подробного изучения обещания, возвращаемого функцией Angular $http. Когда вы упоминаете // любые проверки... вы предполагаете, что это может управлять ответом об ошибке/успехе на основе возвращенного объекта? Это была проблема, против которой я тогда столкнулся. Я знаю, что в идеале ответ всегда будет успешным, но это не всегда так для API, с которым я работаю. Мне нужно выполнить некоторую проверку ответа, чтобы управлять возвращенным состоянием (поэтому обещание Q. раньше казалось хорошим решением).
 – 
JamesEddyEdwards
24 Ноя 2014 в 01:51
Любая дополнительная информация была бы отличной, и спасибо за то, что вы разъяснили выше, ценю это!
 – 
JamesEddyEdwards
24 Ноя 2014 в 01:54
Конечно, это именно то, что я имел в виду под //any validation. если вы считаете, что мой ответ решил вашу проблему, подумайте о том, чтобы принять его (хотя не чувствуйте давления).
 – 
Benjamin Gruenbaum
24 Ноя 2014 в 01:59
Итак, основываясь на вышеизложенном, как бы вы обработали и вернули ошибку (или перехват), если ответ вернул пустую строку? (Например)
 – 
JamesEddyEdwards
24 Ноя 2014 в 12:11

Вот что я обычно делаю

В вызове метода службы:

return $http.post(url,data,{})
    .success(function(response){
        return response.data;
    })
    .error(function(response){
        // return error / status code
    }); // end $http.post

Затем в контроллере:

var data = someSrvc.methodCall(); 

// you could also follow this up with
$q.when(data).then(...);

Или же

В сервисе:

return $http.post(url,data,{});

Затем в контроллере (или где бы то ни было):

someSrvc.methodCall().then(function(response){
    // some success code
},function(response){
    // some error code
}); // end methodCall

Пример $q.when превратить что-то в обещание:

$q.when((someVal <= 0) && (someOtherVal > 0))
    .then(function(){
        // do something when condition is true
    });

Я иногда делаю это, когда я повторно использую массив, но мне нужно, чтобы он был очищен. Самый быстрый способ усечь массив - это удалить все его значения, НЕ устанавливая его длину непосредственно в ноль или устанавливая его в пустой массив. Я знаю, что это кажется нелогичным, но посмотрите сами. Так что в любом случае что-то вроде этого:

while(myArray1.length > 0)
    myArray1.pop();

while(myArray2.length > 0)
    myArray2.pop();

$q.when((myArray1.length <= 0) && (myArray2.length <= 0)).then(function(){
    // do something
});
-1
m.e.conroy 12 Ноя 2014 в 01:20
Спасибо, это здорово. Я не знал, что $http возвращает обещание. Я новичок в Angular, поэтому такая информация действительно полезна.
 – 
JamesEddyEdwards
12 Ноя 2014 в 12:06
Рад помочь
 – 
m.e.conroy
12 Ноя 2014 в 17:31
2
Это полно плохих советов, success не связывает (возвращает одно и то же обещание) - ваше использование $q.when бессмысленно, рискованно и откладывает без причины (нет смысла делать асинхронность, когда это не так). требуется, это просто медленно и запутанно), вы также делаете $q.when без веской причины для вещей, которые уже являются обещаниями.
 – 
Benjamin Gruenbaum
22 Ноя 2014 в 19:53