머리말
AngularJS는 개발하기 쉽고 많은 기능과 좋은 효과를 가지고 있으며 더 많은 응용 프로그램을 만들고 일부 트랩이 수반됩니다. 이 기사에는 AngularJS가 문제가 발생하기 쉬운 몇 가지 일반적인 문제가 나와 있습니다. 함께 살펴 보겠습니다.
1. MVC 디렉토리 구조
둔화되는 AngularJS는 MVC 프레임 워크입니다. 모델은 Backbone.js 프레임 워크만큼 명확하게 정의되지는 않지만 아키텍처는 적절합니다. MVC 프레임 워크에서 작업 할 때 파일 유형별로 분류하는 것이 일반적입니다.
템플릿/ _login.html _feed.htmlapp/ app.js 컨트롤러/ logincontroller.js feedcontroller.js directives/ feedentrydirective.js services/ loginservice.js feedservice.js filters/ capatientialefilter.js
이것은 레일이 동일하다는 것은 말할 것도없이 명백한 구조 인 것 같습니다. 그러나 앱이 확장되기 시작하면이 구조로 인해 한 번에 많은 디렉토리를 열게됩니다. Sublime, Visual Studio 또는 Vim을 Nerd Tree와 결합하여 Directory Tree에서 지속적으로 위아래로 미끄러지는 시간을 투자하게됩니다.
대신 파일을 유형별로 나누는 것과 달리 파일을 특성으로 나눌 수 있습니다.
app/ app.js feed/ _feed.html feedcontroller.js feedentrydirectic.js feedservice.js login/ _login.html logincontroller.js loginservice.js shared/ capatialtefilter.js
이 디렉토리 구조를 사용하면 기능과 관련된 모든 파일을보다 쉽게 찾을 수 있으므로 개발 진행 속도를 높일 수 있습니다. .html 및 .js 파일을 한 곳에 넣는 것은 논란의 여지가 있지만 저장된 시간은 더 가치가 있습니다.
2. 모듈
모든 것을 기본 모듈 아래에 두는 것이 매우 일반적입니다. 소규모 앱의 경우 처음에는 문제가 없지만 곧 무언가가 부정 행위를 할 것임을 알게 될 것입니다.
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 컨트롤러 = Angular.Module ( '컨트롤러', [ '서비스']); controllers.controller ( 'myctrl', function ($ scope, myService) {// controller code}); var app = angular.module ( 'app', [ '컨트롤러', '서비스']);이 방법은 위의 첫 번째 부분에 언급 된 디렉토리 구조와 유사합니다. 충분하지 않습니다. 동일한 철학에 따르면, 특성으로 분류 될 수 있으며, 이는 확장 성으로 이어집니다.
var sharedservicesmodule = angular.module ( 'sharedservices', []); SharedServices.service ( 'NetworkService', function ($ http) {}); var loginModule = Angular.Module ( '로그인', [ 'sharedServices']); loginModule.Service ( 'loginservice', function (NetworkService) {}); loginModule.controller ( 'loginctrl', function ($ scope, loginservice) {}); var app = angular.module ( 'app', [ 'sharedservices', 'login']);큰 응용 프로그램을 개발할 때 단일 페이지에 포함 된 모든 것이 아닐 수도 있습니다. 동일한 유형의 기능을 하나의 모듈에 넣으면 앱에서 모듈을 더 쉽게 재사용 할 수 있습니다.
3. 의존성 주입
의존성 주입은 AngularJS의 가장 좋은 패턴 중 하나이며 테스트를 더 간단하게 만들고 특정 객체에 의존하는 데 분명합니다. AngularJS의 주입 방법은 매우 유연합니다. 가장 쉬운 방법은 종속성 이름을 모듈의 function 로 전달하는 것입니다.
var app = angular.module ( 'app', []); app.controller ( 'mainctrl', function ($ scope, $ timeout) {$ timeout (function () {console.log ($ scope);}, 1000);}); 여기서 mainctrl은 $scope 와 $timeout 에 의존한다는 것이 분명합니다.
생산에 배치 할 준비가되어 있고 코드를 간소화하려고 할 때까지 모든 것이 아름답습니다. uglifyjs를 사용하는 경우 이전 예제는 다음과 같습니다.
var app = angular.module ( "app", []); app.controller ( "mainctrl", function (e, t) {t (function () {console.log (e)}, 1e3)})Angularjs는 Mainctrl이 누구에 의존하는지 어떻게 알 수 있습니까? 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 글로벌 의존성
이것은 종종 AngularJS 프로그램을 작성할 때 발생합니다. 객체는 종속성을 가지며이 객체는 글로벌 범위에 묶여 있으므로이 종속성은 AngularJS 코드에서 사용할 수 있지만 종속성 주입 모델을 파괴하고 특히 테스트 과정에서 일부 문제를 일으 킵니다.
AngularJS를 사용하면 이러한 전역 종속성을 모듈로 쉽게 캡슐화 할 수 있으므로 AngularJS 표준 모듈처럼 주입 할 수 있습니다.
alterscore.js는 기능 스타일로 JavaScript 코드를 단순화하는 훌륭한 라이브러리이며 다음 방법으로 모듈로 변환 할 수 있습니다.
var aUndscore = Angular.Module ( 'aUdterscore', []); alterscore.Factory ( '_', function () {return swooel._; // 밑줄이 이미 페이지에로드되어야 함); var app = angular.Module ( 'app', [ 'oundscore']); app.controller ( 'mainctrl', [ '$ scope', '_', function ($ scope, _) {init = function () {_.keys ($ scope);} init ()]);이 접근법을 사용하면 응용 프로그램이 AngularJS 의존성 주입 스타일로 계속 발전 할 수 있으며 테스트 단계에서 밑줄을 교환 할 수도 있습니다.
이것은 사소하고 불필요하게 보일 수 있지만 코드가 엄격하고 사용해야하는 경우 (그리고 사용해야하는 경우) 이것이 필요합니다.
IV. 컨트롤러 확장
컨트롤러는 AngularJS 고기와 감자이며 조심하지 않으면 특히 처음에 너무 많은 논리를 추가하게됩니다. 컨트롤러는 DOM을 작동 시키거나 DOM 선택기를 유지해서는 안됩니다. 여기서 지침과 NG 모델을 사용해야합니다. 마찬가지로, 비즈니스 논리는 컨트롤러가 아닌 서비스에 존재해야합니다.
데이터는 이미 $ 범위에 묶여 있지 않으면 서비스에 저장해야합니다. 서비스 자체는 싱글 톤이며 응용 프로그램 수명 내내 존재하지만 컨트롤러는 응용 프로그램 상태간에 일시적입니다. 데이터가 컨트롤러에 저장되면 다시 인스턴스화되면 어딘가에서 데이터를 다시 구입해야합니다. 데이터가 LocalStorage에 저장 되더라도 검색 속도는 JavaScript 변수보다 느린 순서입니다.
AngularJS는 단일 책임 원칙 (SRP)을 따를 때 잘 작동합니다. 컨트롤러가 뷰와 모델 사이의 코디네이터 인 경우 가능한 한 적은 논리를 포함해야하므로 테스트를 용이하게합니다.
5. 서비스 대 공장
거의 모든 AngularJS 개발자는 초보자 일 때이 명사에 어려움을 겪고 있습니다. 거의 같은 것을 위해 구문 설탕이기 때문에 실제로 그럴 자격이 없습니다!
AngularJS 소스 코드의 정의는 다음과 같습니다.
기능 공장 (이름, 팩토리프) {return provider (이름, {$ get : factoryfn}); } function service (이름, 생성자) {return factory (이름, [ '$ injector', function ($ injector) {return $ injector.instantiate (생성자);});} 소스 코드에서 서비스가 단순히 factory 함수를 호출하고 후자는 provider 기능을 호출한다는 것을 알 수 있습니다. 실제로 AngularJS는 일부 값, 상수 및 장식에 대한 추가 provider 캡슐화를 제공하며, 이는 비슷한 혼란을 초래하지 않으며 해당 문서가 매우 명확합니다.
서비스는 factory 기능 만 호출하기 때문에 차이점은 무엇입니까? 단서는 $injector.instantiate 에 있습니다 :이 기능에서 $injector service 생성자에서 새 인스턴스를 만듭니다.
다음은 service 와 factory 어떻게 같은 일을하는지 보여주는 예입니다.
var app = angular.module ( 'app', []); app.service ( 'helloorldservice', function () {this.hello = function () {return "Hello World";};}); app.factory ( 'helloworldfactory', function () {return {hello : function () {return "Hello World";}}}); helloWorldService 또는 helloWorldFactory 컨트롤러에 주입되면 모두 "Hello World"를 반환하는 Hello 메소드가 있습니다. service 의 생성자는 선언 될 때 한 번 인스턴스화되며 factory 객체는 주입 될 때마다 전달되지만 여전히 factory 인스턴스는 하나뿐입니다. 모든 providers 는 싱글 톤입니다.
똑같은 일을 할 수 있기 때문에 왜 두 가지 스타일이 필요합니까? service 와 비교하여 factory 기능을 반환 할 수 있기 때문에 더 많은 유연성을 제공하며 나중에 만들 수 있습니다. 이는 객체 지향 프로그래밍에서 공장 패턴의 개념을 충족시킵니다. 여기서 공장은 다른 객체를 생성 할 수있는 객체가 될 수 있습니다.
app.factory ( 'hellofactory', function () {return function (name) {this.name = name; this.hello = function () {return "hello" + this.name;};};};}); 다음은 service 와 두 factory 사용하는 컨트롤러의 예입니다. helloFactory 새 객체가 생성 될 때 name 값을 설정하는 함수를 반환합니다.
app.controller ( 'helloctrl', function ($ scope, helloworldservice, helloworldfactory, hellofactory) {init = function () {helloworldservice.hello (); // 'hello'helloworldfactory.hello (// 'hello' init ();});초보자가되면 서비스 만 사용하는 것이 가장 좋습니다.
Factory 또한 많은 개인 방법으로 수업을 설계 할 때 유용합니다.
app.factory ( 'privateFactory', function () {var privatefunc = function (name) {return name.split ( ""). reverse (). join ( ""); // 이름을 반대로 반전}; return {hello : function (name) {return "hello" + privatefunc (name);}}); 이 예를 들어, privateFunc 메소드를 privateFactory 의 공개 API에 사용할 수 없게 만들 수 있습니다. 이 패턴은 service 에서 수행 할 수 있지만 factory 에서는 더 쉽습니다.
6. 바타 랑은 사용되지 않습니다
Batarang은 AngularJS 앱을 개발하고 테스트하기위한 우수한 Chrome 플러그인입니다.
Batarang은 모델을 찾아 볼 수있는 기능을 제공하여 AngularJS가 범위에 어떻게 결합되는지 관찰 할 수있는 기능을 제공합니다. 이는 지침을 처리하고 범위의 범위를 분리 할 때 매우 유용합니다.
Batarang은 또한 종속성 그래프를 제공합니다.이 그래프는 테스트되지 않은 코드 기반에 노출되면 유용하여 어떤 서비스에 집중 해야하는지 결정할 수 있습니다.
마지막으로 Batarang은 성능 분석을 제공합니다. Angular는 패키지로 사용될 수 있으며 성능이 우수하지만 사용자 정의 지침과 복잡한 논리로 가득 찬 응용 프로그램에는 부드럽 지 않습니다. Batarang Performance 도구를 사용하면 Digest주기에서 가장 긴 기능이 가장 오래 실행되는 기능을 직접 관찰 할 수 있습니다. 성능 도구는 또한 완전한 시계 트리를 보여줄 수 있으며, 이는 많은 감시자가있을 때 유용합니다.
7. 너무 많은 감시자
이전 시점에서 우리는 AngularJS가 패키지로 사용될 수 있으며 성능이 우수하다고 언급했습니다. 더러운 데이터 점검은 한 번의 다이제스트 주기로 완료해야하므로, 시청자 수가 약 2000으로 증가하면이주기는 중대한 성능 문제를 일으킬 것입니다. (2000 년은 상당한 성능 하락을 일으킨다 고 말할 수는 없지만 이것은 좋은 경험적 가치입니다. AngularJS 1.3 릴리스 버전에서는 이미 다이제스트주기를 엄격하게 제어 할 수있는 몇 가지 변화가 있습니다.)
다음 "즉시 실행 함수 표현식 (IIFE)"은 현재 페이지의 모든 감시자 수를 인쇄합니다. 단순히 콘솔에 붙여 넣고 결과를 관찰 할 수 있습니다. 이 iife는 stackoverflow에 대한 Jared의 답변에서 파생되었습니다.
(function () {var root = $ (document.getElementsByTagName ( 'body')); var watchers = []; var f = function (element) {if (exement.data (). hasOwnProperty ( '$ scope')) {Angular.foreach (exement.data (). $ scope. $$ watchers, function (watcher)); angular.foreach (element.children (childlement) {f (childlement);};이런 식으로, 바타 랑 성능 섹션의 시계 트리와 결합 된 감시자의 수를 얻으려면 중복 코드가 존재하는 위치 또는 일정한 데이터가있는 위치 및 시계도 확인해야합니다.
변경되지 않은 데이터가 있고 AngularJS를 사용하여 템플릿을 사용하려면 Bindonce 사용을 고려할 수 있습니다. Bindonce는 AngularJS에서 템플릿을 사용할 수있는 간단한 지침이지만 시계에 추가되지 않으므로 시계 수가 증가하지 않도록합니다.
8. 제한된 범위의 $ 범위
JavaScript 프로토 타입 기반 상속은 객체 지향 객체 지향에서 클래스 기반 상속과 미묘한 차이를 가지고 있으며, 이는 일반적으로 문제가되지 않지만이 미묘함은 $scope 사용할 때 나타납니다. AngularJS에서 각 $scope 부모 $scope 상속받습니다. 이는 최고 수준에서 $rootScope 라고합니다. ( $scope 는 전통적인 지시문과 다소 다릅니다. 특정 행동 범위가 있으며 명시 적으로 선언 된 속성 만 상속합니다.)
프로토 타입 상속의 특성으로 인해 부모와 자식 수업간에 데이터를 공유하는 것은 중요하지 않지만주의하지 않으면 부모 $scope 의 속성을 오용하기가 쉽습니다.
예를 들어, 로그인 양식에 입력 된 탐색 표시 줄에 사용자 이름을 표시해야합니다. 다음 시도는 작동해야합니다.
<div ng-controller = "navctrl"> <span> {{user}} </span> <div ng-controller = "loginctrl"> <span> {{user}} </span> <입력 ng-model = "user"> </input> </div>질문은 ... : 사용자의 NG 모델이 텍스트 입력에 설정됩니다. 사용자가 컨텐츠를 입력하면 어떤 템플릿이 업데이트됩니까? navctrl 또는 loginctrl 또는 전부?
loginctrl을 선택했다면 프로토 타입 상속이 어떻게 작동하는지 이해했을 것입니다.
리터럴을 검색 할 때 프로토 타입 체인이 작동하지 않습니다. Navctrl도 동시에 업데이트되면 프로토 타입 체인을 검색해야합니다. 그러나 값이 객체라면 이런 일이 일어날 것입니다. (JavaScript에서는 함수, 배열 및 객체가 모두 객체임을 기억하십시오)
따라서 예상되는 동작을 얻으려면 navctrl에 객체를 만들어 loginctrl에서 참조 할 수 있습니다.
<div ng-controller = "navctrl"> <span> {{user.name}} </span> <div ng-controller = "loginctrl"> <span> {{user.name}} </span <input ng-model = "user.name "> </div> </div> 이제 사용자는 객체이므로 프로토 타입 체인이 작동하고 Navctrl 템플릿과 $scope 및 loginCtrl 업데이트됩니다.
이것은 꽤 인공적인 예처럼 보이지만,이 문제는 특정 지침을 사용하여 ngRepeat 와 같은 자식 $scope 만들 때 쉽게 발생할 수 있습니다.
9. 수동 테스트
TDD가 모든 개발자가 선호하는 방식이 아닐 수도 있으므로 코드가 작동하는지 또는 다른 것에 영향을 미치는지 확인할 때 수동 테스트를 수행합니다.
AngularJS 앱을 테스트하지 않는 것은 말이되지 않습니다. AngularJS는 처음부터 테스트 할 수 있도록 설계되었으며 종속성 주입 및 NGMock 모듈이 이에 대한 증거입니다. AngularJS의 핵심 팀은 다음 단계로 테스트 할 수있는 수많은 도구를 개발했습니다.
9.1 오기체
단위 테스트는 테스트 작업의 기초이지만 앱의 복잡성이 점점 더 복잡해지면 통합 테스트가 실제 상황에 더 가깝습니다. 다행히도 AngularJS의 핵심 팀은 필요한 도구를 제공했습니다.
우리는 사용자 상호 작용을 시뮬레이션하기위한 엔드 투 엔드 테스터 인 Protractor를 설립하여 AngularJS 프로그램의 건강을 확인하는 데 도움이 될 수 있습니다.
Protractor는 Jasmine Test Framework를 사용하여 테스트를 정의합니다. Protractor는 다른 페이지 상호 작용 동작에 대해 매우 강력한 API를 가지고 있습니다.
우리는 다른 엔드 투 엔드 테스트 도구를 가지고 있지만, 돌출부의 장점은 특히 $ 다이제스트주기에서 AngularJS 코드와 함께 작업하는 방법을 이해한다는 것입니다.
9.2 카르마
Protractor와의 통합 테스트 작성을 완료하면 다음 단계는 테스트를 실행하는 것입니다. 테스트가 실행되기를 기다리는 것은 특히 통합 테스트는 모든 개발자에게 희미한 슬픔입니다. AngularJS의 핵심 팀도 극도로 고민을 느꼈기 때문에 업장을 개발했습니다.
Karma는 피드백 루프를 끄는 데 도움이되는 테스터입니다. Karma는 지정된 파일이 변경되면 테스트를 실행 하므로이 작업을 수행 할 수 있습니다. Karma는 여러 브라우저에서 테스트를 실행할 것이며 다른 장치는 Karma 서버를 가리킬 수있어 실제 응용 프로그램 시나리오를 더 잘 다룰 수 있습니다.
10. jQuery를 사용하십시오
JQuery는 표준화 된 크로스 플랫폼 개발을 갖춘 멋진 라이브러리이며 현대적인 웹 개발에 거의 필요합니다. 그러나 jQuery의 많은 훌륭한 특징에도 불구하고 철학은 AngularJS와 일치하지 않습니다.
AngularJS는 앱을 구축하기위한 프레임 워크이며 JQuery는 "HTML 문서 작업, 이벤트 처리, 애니메이션 및 Ajax"를 단순화하는 라이브러리입니다. 이것은 둘 사이의 가장 기본적인 차이입니다. AngularJS는 프로그램의 아키텍처에 전념하며 HTML 페이지와 관련이 없습니다.
AngularJS 프로그램을 구축하는 방법을 더 잘 이해하려면 jQuery 사용을 중지하십시오. JQuery를 사용하면 개발자가 기존 HTML 표준의 문제에 대해 생각할 수 있지만 문서에서 알 수 있듯이 "AngularJS는 응용 프로그램에서 HTML이라는 용어를 확장 할 수 있습니다."
DOM 운영은 지침으로 만 수행해야하지만 jQuery 만 캡슐화 할 수 있다는 의미는 아닙니다. jQuery를 사용하기 전에이 기능이 이미 AngularJS에서 제공되는지 여부에 대해 항상 생각해야합니다. 지침이 서로 의존 할 때 강력한 도구를 만드는 것은 정말 강력합니다.
그러나 하루가 올 때 정말 위대한 jQuery는 필수적이지만, 처음에 그것을 소개하는 것은 일반적인 실수입니다.
요약
AngularJS는 커뮤니티의 도움으로 항상 개선하는 훌륭한 프레임 워크입니다. AngularJS는 여전히 진화하는 개념이지만, AngularJS 응용 프로그램 개발에서 발생하는 문제를 피하기 위해 사람들이 위에서 언급 한 규칙을 따를 수 있기를 바랍니다. 이 기사의 내용이 모든 사람에게 도움이되기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.