Топ10 ошибок, совершаемых при разработке на AngularJS

Топ10 ошибок, совершаемых при разработке на AngularJS

989
ПОДЕЛИТЬСЯ

Так как все провайдеры синглтоны, у нас постоянно будет лишь один экземпляр сервиса и один экземпляр фабрики. AngularJS дозволяет оборачивать подобные объекты в модули так, что они могут быть внедрены подобно обыденным AngularJS модулям. 5. Неиспользование Batarang Batarang — это расширение браузера Chrome для разработки и дебага AngularJS приложений. Раздувание контроллеровКонтроллеры — это база AngularJS. Модули (либо их отсутствие)Нередко, в начале разработки проекта весь функционал складывается в единый модуль. Внедрение зависимостейВнедрение зависимостей (dependency injection) одна из наилучших способностей, предоставляемых AngularJS. Чтоб этого не происходило, есть чрезвычайно обычное решение — передавать зависимости как массив строк, с крайним элементом в виде функции, принимающей все перечисленные зависимости в виде характеристик:app.controller(‘MainCtrl’, [‘$scope’, ‘$timeout’, function($scope, $timeout){
$timeout(function(){
console.log($scope);
}, 1000);
}]);
Код выше будет преобразован минификатором в код, который AngularJS уже сумеет корректно интерпретировать:app.controller("MainCtrl",["$scope","$timeout",function(e,t){t(function(){console.log(e)},1e3)}])
3.1. Точно также и бизнес-логика обязана находиться в сервисах. Структура папок, соответственная MVC приложениямAngularJS является MVC фреймворком. Композиция легкости в разработке и огромное количество способностей привели к широкому распространению, а совместно с распространением возникли обычные, нередко встречающиеся ошибки. Чтоб избежать этого, вы сможете группировать файлы по функционалу, а не по типу:app/
app.js
Feed/
_feed.html
FeedController.js
FeedEntryDirective.js
FeedService.js
Login/
_login.html
LoginController.js
LoginService.js
Shared/
CapatalizeFilter.js
Схожая структура папок делает еще наиболее обычным поиск связанных файлов, относящихся к одной и той же фиче, что способно убыстрить процесс разработки. Самый обычный метод — это передать зависимость в функцию в качестве параметра:var app = angular.module(‘app’,[]);
app.controller(‘MainCtrl’, function($scope, $timeout){
$timeout(function(){
console.log($scope);
}, 1000);
});
Из кода ясно, что MainCtrl зависит от $scope and $timeout. Невзирая на то, что модели в нем определяются не так очевидно, как в случае с backbone.js, общий строительный стиль остается тем же. 4. 3. До какого-то момента схожий подход работает, но по мере развития проекта код становится неуправляемым.var app = angular.module(‘app’,[]);
app.service(‘MyService’, function(){
//service code
});

app.controller(‘MyCtrl’, function($scope, MyService){
//controller code
});
Последующим по распространенности подходом является группировать объекты по их типу:var services = angular.module(‘services’,[]);
services.service(‘MyService’, function(){
//service code
});

var controllers = angular.module(‘controllers’,[‘services’]);
controllers.controller(‘MyCtrl’, function($scope, MyService){
//controller code
});

var app = angular.module(‘app’,[‘controllers’, ‘services’]);
Схожий подход масштабируется тоже не наилучшим образом, подобно структуре каталогов из пт 1. Тем не наименее при росте приложения внедрение схожей структуры папок приводит к тому, что в каждый момент времени приходится держать открытыми несколько папок. Пример сервиса и фабрики, выполняющих однообразные деяния:var app = angular.module(‘app’,[]);

app.service(‘helloWorldService’, function(){
this.hello = function() {
return "Hello World";
};
});

app.factory(‘helloWorldFactory’, function(){
return {
hello: function() {
return "Hello World";
}
}
});
В момент, когда helloWorldService либо helloWorldFactory будут инжектированы в контроллер, они обе будут иметь единственный способ, ворачивающий «Hello World». И нередко, в особенности новенькие, пишут в контроллерах очень много логики. Контроллеры не должны осуществлять манипуляции с DOM либо содержать DOM селекторы, для это есть директивы. AngularJS чрезвычайно гибок в вопросце того, как зависимости могут быть внедрены. Его внедрение упрощает процесс разработки , делая AngularJS великолепным инвентарем для сотворения маленьких интернет-приложений, но способности фреймворка не ограничиваются сиим и разрешают разрабатывать огромные, заполненные различным функционалом приложения. В этом топике описаны более всераспространенные ошибки, встречающиеся при разработке на AngularJS огромных проектов. Раз service просто вызывает функцию factory, в чем разница меж ними? Это отлично работает до того момента, как проект пойдет в продакшн и вы захотите минифицировать ваш код. К примеру, великолепная библиотека Underscore.js может быть завернута в модуль последующим образом: var underscore = angular.module(‘underscore’, []);
underscore.factory(‘_’, function() {
return window._; //Underscore must already be loaded on the page
});
var app = angular.module(‘app’, [‘underscore’]);

app.controller(‘MainCtrl’, [‘$scope’, ‘_’, function($scope, _) {
init = function() {
_.keys($scope);
}

init();
}]);
Это дозволяет приложению применять единый стиль с неотклонимым внедрением зависимостей и оставляет возможность тестировать модули в отрыве от функционала их зависимостей. 1. Глобальные зависимостиЧасто, при разработке AngularJS приложения, возникает необходимость в использовании объектов, доступных в хоть какой точке приложения. Чем бы вы не воспользовались — Sublime, Visual Studio либо Vim с NerdTree — при перемещении по дереву каталогов вы повсевременно будете растрачивать время на скроллинг. В ООП фабрика представляет собой объект, создающий остальные объекты:app.factory(‘helloFactory’, function() {
return function(name) {
this.name = name;

this.hello = function() {
return "Hello " + this.name;
};
};
});
Вот пример контроллера, использующего сервис и две фабрики:app.controller(‘helloCtrl’, function($scope, helloWorldService, helloWorldFactory, helloFactory) {
init = function() {
helloWorldService.hello(); //’Hello World’
helloWorldFactory.hello(); //’Hello World’
new helloFactory(‘Readers’).hello() //’Hello Readers’
}

init();
});
Фабрики также могут быть полезны при разработке классов с приватными способами:app.factory(‘privateFactory’, function(){
var privateFunc = function(name) {
return name.split("").reverse().join(""); //reverses the name
};

return {
hello: function(name){
return "Hello " + privateFunc(name);
}
};
});
6. Нередко используемой практикой при использовании MVC фреймворков является группировка файлов по последующему шаблону:templates/
_login.html
_feed.html
app/
app.js
controllers/
LoginController.js
FeedController.js
directives/
FeedEntryDirective.js
services/
LoginService.js
FeedService.js
filters/
CapatalizeFilter.js
Схожий подход встречается нередко, в особенности у разрабов, имеющих опыт разработки на RoR. Фабрики предоставляют больше гибкости, так как они могут возвращать функцию, которая может создавать новейшие объекты. Внедрение UglifyJS к вышеуказанному коду приведет к последующему:var app=angular.module("app",[]);app.controller("MainCtrl",function(e,t){t(function(){console.log(e)},1e3)})
Сейчас AngularJS никак не выяснит от чего же в действительности зависит MainCtrl. Да, это может показаться спорным — хранить в одной папке html файлы совместно с js, но эффект от экономии времени может оказаться наиболее принципиальным.2. DI упрощает процесс тестирования и делает код чище. Так почему же есть сразу и фабрики и сервисы, раз они выполняют одну и ту же функцию? Чтоб достигнуть наилучшей масштабируемости, мы последуем той же самой концепции разбиения кода по фичам:var sharedServicesModule = angular.module(‘sharedServices’,[]);
sharedServices.service(‘NetworkService’, function($http){});

var loginModule = angular.module(‘login’,[‘sharedServices’]);
loginModule.service(‘loginService’, function(NetworkService){});
loginModule.controller(‘loginCtrl’, function($scope, loginService){});

var app = angular.module(‘app’, [‘sharedServices’, ‘login’]);
Разнесение функционала по разным модулям также дает возможность повторного использования кода в разных проектах. Смысл в $injector.instantiate, снутри которой $injector делает новейший экземпляр функции конструктора сервиса. На реальный момент AngularJS — один из самых фаворитных javascript фреймворков. Service vs FactoryЭти именования приводят в конфуз каждого новенького в AngularJS, хотя в действительности они практически схожи.Поглядим начальные коды AngularJS:function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}

function service(name, constructor) {
return factory(name, [‘$injector’, function($injector) {
return $injector.instantiate(constructor);
}]);
}
Функция service просто вызывает функцию factory, в которую обернут вызов функции provider. Batarang дозволяет: Это разламывает стройную модель, основанную на внедрении зависимостей, и приводит к появлению багов и усложнению процесса тестирования. Данные также должны храниться в сервисах (за исключением случаев когда данные привязаны к $scope), так как сервисы, в отличие от контроллеров, синглтоны, чье время жизни совпадает со временем жизни самого приложения.При разработке контроллеров лучше всего следовать принципу единственной ответственности (SRP) и считать контроллер координатором меж представлением и моделью, в этом случае логики в нем будет минимум.
просматривать модели привязанные к скоупам
строить граф зависимостей в приложении
создавать анализ производительности приложения
Внедрение jQueryjQuery восхитительная библиотека. Невзирая на то, что jQuery владеет огромным количеством фич, её философия далека от философии AngularJS. Наследование скоупов ($scope’s)Наследование в JS основанное на макетах различается от классического наследования на классах. В AngularJS обыденный (не изолированный) $scope наследован от родительского до самого старшего предка $rootScope. habrahabr.ru AngularJS был вначале спректирован таковым образом, чтоб разработанный на нем код был тестируемым. В этом заключается базовое различие меж ними. AngularJS — это фреймворк для построения приложений, в то время как jQuery — это просто библиотека, упрощающая процесс взаимодействия JavaScript и HTML и предоставляющая удачный API для работы с AJAX. Она стандартизовала кросс-платформенную разработку и стала эталоном в современной интернет-разработке. Чтоб вправду понять принципы построения AngularJS приложений, для вас стоит закончить применять JQuery. Также есть несколько инструментов, способных вас перенести на последующий уровень.9.1 Protractor Юнит-испытания — это база для построения всеполноценно покрытого тестами приложения, но с ростом проекта внедрение интеграционных тестов может быть наиболее действенным для проверки, как жизнеспособен код в приложении. Ангуляр — это подход к построению приложений, а не метод управления разметкой документа. jQuery принуждает вас соответствовать существующему HTML эталону, в то время как ангуляр дозволяет для вас расширять эталон HTML под нужды вашего приложения. 9.2. 10. Раз ваш ответ — loginCtrl, вы осознаете, как работает наследование основанное на макетах. Чтоб достигнуть хотимого поведения, нам лучше применять объект для корректного обновления имени юзера в дочернем и родительском $scope. В поиске по строковым полям цепочка прототипов не употребляется. Манипуляции с DOM в AngularJS должны производиться в директивах, но при этом полностью допустимо располагать в директивах обертки над существующими jQuery компонентами, раз вы не смогли отыскать аналог на angular.ЗаключениеAngularJS — это великолепный, повсевременно совершенствующийся фреймворк с хорошим комьюнити. Посреди множества разных инструментов для тестирования у Protractor есть преимущество в осознании внутреннего устройства AngularJS, что в особенности полезно, когда вы имеет дело с чем-то наподобие $digest циклов. Нет оправданий для использования подобного подхода в случае с AngularJS. В случае с неизменяемыми данными вы сможете применять директиву bindonce, чтоб не наращивать количество наблюдателей на страничке.8. Хотя достижение числа 2000 не гарантирует замедления, это отменная стартовая точка, с которой уже можно начинать волноваться. DI, ngMock — ваши фаворитные ассистенты в этом. Невзирая на то, что производительность AngularJS хорошая «из коробки», при росте приложения, с добавлением кастомных директив и сложной логики, приложение может начать подтормаживать. Надеюсь, мой перечень фаворитных ошибок понадобится для вас в вашей работе. Karma Команда проекта AngularJS не ограничилась написанием инвентаря для разработки тестов. Используя Batarang просто разобраться, какая из функций растрачивает много времени при вызове. Традиционно это не является неувязкой, но эти аспекты могут проявляться при работе со скоупами. Karma дозволяет делать испытания каждый раз при изменении файлов с исходниками. Очень много наблюдателейКак было отмечено выше, AngularJS достаточно производителен из коробки. К счастью, команда AngularJS разработала превосходный инструмент — Protractor, способный имитировать взаимодействие с юзером. Также был разработан исполнитель тестов (test runner) Karma. С помощью последующего кода можно выяснить количество наблюдателей на страничке:(function () {
var root = $(document.getElementsByTagName(‘body’));
var watchers = [];

var f = function (element) {
if (element.data().hasOwnProperty(‘$scope’)) {
angular.forEach(element.data().$scope.$$watchers, function (watcher) {
watchers.push(watcher);
});
}

angular.forEach(element.children(), function (childElement) {
f($(childElement));
});
};

f(root);

console.log(watchers.length);
})();
Используя код выше и дерево наблюдателей батаранга, вы сможете поглядеть, есть ли у вас наблюдатели-дубликаты либо наблюдатели над неизменяемыми данными. Внедрение ручного тестированияДо тех пока вы не начнете применять TDD в собственной работе, для вас придется каждый раз запускать проект и проводить ручное тестирование, чтоб удостовериться, что ваш код работает. Karma способна делать испытания параллельно в пары браузерах. Общественная модель данных, разделяемая родительским скоупом с дочерним, организуется просто благодаря наследованию на макетах. Разные устройства также могут быть нацелены на сервер кармы для наиболее полного покрытия настоящих сценариев использования. Protractor употребляет фреймворк Jasmine для написания тестов и владеет неплохим API для описания разных сценариев взаимодействия. Batarang также показывает дерево наблюдателей (watch tree), которое может быть полезным при использовании огромного числа наблюдателей (watchers).7. В последующем примере мы желаем, чтоб имя юзера сразу отображалось в 2-ух элементах span, опосля того как юзер введет свое имя.<div ng-controller="navCtrl">
<span>{{user}}</span>
<div ng-controller="loginCtrl">
<span>{{user}}</span>
<input ng-model="user"></input>
</div>
</div>
Сейчас вопросец: когда юзер введет свое имя в текстовое поле, в каких элементах оно будет отображаться:navCtrl, loginCtrl, либо в обоих? (Припоминаю, что в JS функции и массивы также являются объектами.)<div ng-controller="navCtrl">
<span>{{user.name}}</span>
<div ng-controller="loginCtrl">
<span>{{user.name}}</span>
<input ng-model="user.name"></input>
</div>
</div>
Сейчас, так как переменная user — объект, цепочка прототипов будет работать и элемент span в navCtrl будет корректно обновлен совместно с loginCtrl. Это может смотреться ненатуральным примером, но при работе с директивами, создающими дочерние скоупы (подобно ngRepeat), подобные моменты будут возникать.9. Но, когда количество наблюдателей достигнет числа 2000, $digest цикл, в котором происходит проверка конфигурации данных, может начать замедлять работу приложения.

НЕТ КОММЕНТАРИЕВ

ОСТАВЬТЕ ОТВЕТ

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.