Или давайте наконец-то уже писать promises «человеческим» языком!
Асинхронные взаимодействия в AngularJS построены на promise. Я не хочу рассматривать в данной записи подробно теорию promise, так что, рассмотрим лучше их применение.
Все чаще в коде разработчиков встречаются использование promise. Но увы, использование оставляет желать лучшего. Не представляю от куда зародился такой «анти-паттерн», но он усердно прорастает почти в каждом коде разработчика.
Собственно, пример ниже,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function caller(){ callee({}, function(){}, function(){}); } function callee(toSave, success, failure){ var promise = $http.post("/place", toSave); promise.success(function(successData){ if(success){ success(successData); } }); failure.error(function(errorData){ if(failure){ failure(errorData); } }); } |
Прежде чем раздуть holy war, вы конечно можете спросить — «что же тут не верно? «, собственно «почти» все верно и даже может быть приемлемо в некоторых случаях. Как видно из кода, мы стараемся разделить обработчики, абстрактные обратные вызовы и код более менее чистый. Однако, при таком подходе использования promise, мы столкнемся с некоторыми проблемами. Собственно, давайте обсудим все по порядку.
День первый: Initial code
В один пятничный день, сидя на работе и попивая чай, к Вам вдруг подбегает менеджер со словами — «Нам нужна страничка, которая сохраняет элемент, а затем переходит в другой раздел (другую страницу)».
Нет проблем, мы ведь гуру программирования и за пару минут пишем примерно вот такой код,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
//Page controller angular.module("app").controller("testCtrl", function($scope, $location, test){ /** * Обработчик при нажатие на кнопку сохранить * Сохраняет item и при success переходит на другую страницу */ $scope.onSaveClick = function(){ test.saveItem($scope.data.item, //success callback function(){ $scope.data.backgroundColor = "red"; //go to next page $location.path("/place1"); }, //error callback function(){ //go to next page $location.path("/place2"); }); } } //Helper service angular.module("app").service("test", function(){ function saveItem(item, success, fail){ var promise = $http.post("/item", item); //оборачиваем callback в другой callback, это ведь круто promise.success(function(itemData){ if(success){ success(itemData); } }); //тут делаем другой прием. Потому что, 2 пути всегда круче одного! promise.error(fail); } return { saveItem : saveItem } }) |
И вуаля, код для нашей страницы готов! Все работает как и было задуманно. Я почти уверен, что большая часть разработчиков написали бы именно такой код (не лукавте, все, хотя бы один раз именно так и писали) .