AngularJS에서 데이터 바인딩은 어떻게 작동합니까?


1956

데이터 바인딩은 어떻게 작동합니까? AngularJS프레임 워크 합니까?

나는 그들의 사이트 에서 기술적 인 세부 사항을 찾지 못했다 . 데이터가 뷰에서 모델로 전파 될 때 작동 방식이 다소 명확합니다. 그러나 AngularJS는 세터와 게터없이 모델 속성의 변경을 어떻게 추적합니까?

이 작업을 수행 할 수있는 JavaScript 감시자가 있다는 것을 알았 습니다. 그러나 Internet Explorer 6Internet Explorer 7 에서는 지원되지 않습니다 . AngularJS는 예를 들어 다음과 같이 변경 하고이 변경 사항을 뷰에 반영했다는 것을 어떻게 알 수 있습니까?

myobject.myproperty="new value";

10
앵귤러 1.0.0rc1 이후로 모더가 즉시 업데이트되도록 ng-model-instant ( docs-next.angularjs.org/api/… )를 지정해야합니다. 그렇지 않으면 블러 이벤트에서 업데이트됩니다.
Sotomajor

8
: 마르첼로의 링크는 분명히 다시, 그래서 여기에 고장 github.com/mhevery/angular.js/blob/master/docs/content/guide/...
하충 민의

6
@ orian, 그 링크는 나쁘다. - (I 가정)으로 업데이트는 동일 docs.angularjs.org/guide/databinding
케빈 메러디스

11
이 질문을 여전히 읽고있는 사람들은 Angular 2.0이 웹 구성 요소를 사용하고 아래 답변의 많은 문제를 해결하기 위해 Angular 1.x 이후 데이터 바인딩에 대한 방식을 크게 변경했습니다.
aug

답변:


2744

AngularJS는 값을 기억하여 이전 값과 비교합니다. 이것은 기본적인 더티 체크입니다. 값이 변경되면 변경 이벤트가 시작됩니다.

$apply()당신이, AngularJS와 세계로 비 AngularJS와 세계에서 통화를 전환 할 때 부르는 방법 $digest(). 다이제스트는 단순한 오래된 더러운 검사입니다. 모든 브라우저에서 작동하며 완전히 예측 가능합니다.

더티 검사 (AngularJS)와 변경 리스너 ( KnockoutJSBackbone.js ) 를 대조하려면 : 더티 검사는 간단하고 비효율적 일 수 있지만 (나중에 설명하겠습니다), 의미 상 항상 올바른 것으로 밝혀졌습니다. 변경 리스너에는 이상한 경우가 많고 의미 론적으로보다 정확하게하려면 종속성 추적과 같은 것이 필요합니다. KnockoutJS 종속성 추적은 AngularJS에없는 문제에 대한 영리한 기능입니다.

변경 리스너 관련 문제 :

  • 브라우저는 기본적으로이를 지원하지 않기 때문에 구문은 끔찍합니다. 그렇습니다. 프록시가 있지만 모든 경우에 의미 적으로 정확하지는 않으며 이전 브라우저에는 프록시가 없습니다. 결론은 더티 검사를 통해 POJO 를 수행 하는 반면 KnockoutJS와 Backbone.js는 클래스에서 상속하고 접근자를 통해 데이터에 액세스하도록하는 것입니다.
  • 유착을 변경하십시오. 항목 배열이 있다고 가정하십시오. 추가 할 때마다 반복 할 때 항목을 배열에 추가하려고한다고 가정하면 변경 할 때마다 이벤트가 발생하여 UI가 렌더링됩니다. 이것은 성능이 매우 나쁩니다. 원하는 것은 마지막에 UI를 한 번만 업데이트하는 것입니다. 변경 이벤트가 너무 세분화되었습니다.
  • 변경 리스너는 setter에서 즉시 실행되는데, 이는 변경 리스너가 데이터를 추가로 변경하여 더 많은 변경 이벤트를 발생 시키므로 문제가됩니다. 스택에서 한 번에 여러 변경 이벤트가 발생할 수 있기 때문에 이것은 좋지 않습니다. 어떤 이유로 든 동기화를 유지해야하는 두 개의 어레이가 있다고 가정하십시오. 둘 중 하나만 추가 할 수 있지만, 추가 할 때마다 변경 이벤트가 발생하여 이제 세계에 대한 일관성이 없습니다. 이는 각 콜백이 독점적으로 실행되어 완료되기 때문에 JavaScript가 피하는 스레드 잠금과 매우 유사한 문제입니다. 변경 이벤트는 세터가 의도하지 않았고 명백하지 않은 광범위한 결과를 가질 수 있으므로 스레드 문제가 다시 발생하기 때문에이를 중단시킵니다. 당신이하고 싶은 일은 리스너 실행을 지연시키고 보장하는 것입니다.

성능은 어떻습니까?

더티 검사는 비효율적이므로 속도가 느릴 수 있습니다. 이론적 인 논증이 아닌 실수를 찾아야하지만 먼저 제약을 정의 해 보자.

인간은 :

  • 느림 — 50ms보다 빠른 것은 인간이 인식 할 수 없으므로 "인스턴트"로 간주 될 수 있습니다.

  • 제한 — 실제로 한 페이지에 약 2000 개 이상의 정보를 사람에게 보여줄 수 없습니다. 그 이상은 정말 나쁜 UI이며 인간은 어쨌든 이것을 처리 할 수 ​​없습니다.

실제 질문은 이것입니다. 브라우저에서 50ms 이내에 얼마나 많은 비교를 할 수 있습니까? 많은 요소가 작용함에 따라 대답하기 어려운 질문이지만 다음은 테스트 사례입니다. http://jsperf.com/angularjs-digest/6 10,000 명의 감시자를 만듭니다. 최신 브라우저에서는 6ms 미만입니다. 에 인터넷 익스플로러 8 은 40 밀리 초 정도 걸립니다. 보시다시피, 이것은 요즘 느린 브라우저에서도 문제가되지 않습니다. 주의 사항 : 제한 시간에 맞추기 위해서는 비교가 간단해야합니다 ... 불행히도 AngularJS에 느린 비교를 추가하는 것은 너무 쉬운 방법이므로, 당신이 무엇을 모르는 경우 느린 응용 프로그램을 쉽게 구축 할 수 있습니다 하고있다. 그러나 우리는 인스 트루먼 테이션 모듈을 제공함으로써 어느 것이 느리게 비교되는지를 보여줄 수 있기를 희망합니다.

비디오 게임과 GPU는 특히 일관성이 있기 때문에 더티 검사 방식을 사용하는 것으로 나타났습니다. 모니터 재생 빈도 (일반적으로 50-60Hz 또는 16.6-20ms마다)를 초과하는 한, 그 이상의 성능은 낭비이므로 FPS를 높이는 것보다 더 많은 것을 그리는 것이 좋습니다.


32
@Mark-예, KO에서는 .extend ({throttle : 500})을 추가하여 마지막 변경 이벤트 후 500 밀리 초 동안 대기합니다.
다니엘 Earwicker

158
이 전체 답변은 "50fps를 얻는 한, 인간의 눈으로는 그것을 인식 할 수 없기 때문에 성능이 낭비입니다. 따라서 fps를 높이는 것보다 더 많은 것을 그리는 것이 좋습니다." 해당 진술은 응용 프로그램에 따라 완전히 틀립니다. 눈은 50fps 이상을 확실히 인식 할 수 있으며 VR 쇼 (John Carmack 또는 Michael Abrash의 최신 기사 중 특히 GDC 2013 VR 이야기를 읽음)의 다양한 문제로 인해 50fps는 실제로 너무 느립니다. 그 외에는 대답이 훌륭합니다. 나는 단지 잘못된 정보 확산을 원하지 않습니다.
네이트 번디

10
@DavidRivers 우리는 utorrent 1µs = 0.000001s에서와 같이 µs입니다
Thorgeir

33
이 진술은 "더러운 점검은 녹아웃이없는 문제에 대한 영리한 기능"이라고 쉽게 역설 할 수 있습니다. ES6은 관찰 가능 항목을 사용하고 있으며 각도 검사는 더티 검사를 제거합니다. 현실 세계는이 대답을 따라 잡았고 그것이 틀린 것으로 보여 주었다.
원뿔

17
"50ms보다 빠른 것은 인간이 알아볼 수없는 것"이 ​​아닙니다. 테스트 결과 고객은 50ms 업데이트 대기 시간 (20fps)과 16.6ms 업데이트 대기 시간 (60fps)을 쉽게 구분할 수 있습니다. 이전 속도로 실행되는 장면은 사람들이 의식적으로 프레임 속도를 등록하지 않은 경우에도 전반적으로 "느낌이 어떻습니까"등급이 지속적으로 떨어집니다.
Crashworks

323

Misko는 이미 데이터 바인딩의 작동 방식에 대한 훌륭한 설명을 제공했지만 데이터 바인딩의 성능 문제에 대한 견해를 추가하고 싶습니다.

Misko가 언급했듯이 약 2000 개의 바인딩이 문제를 발견하기 시작하는 곳이지만 페이지에 2000 개 이상의 정보가 없어야합니다. 이것은 사실 일 수 있지만 모든 데이터 바인딩이 사용자에게 표시되는 것은 아닙니다. 양방향 바인딩으로 모든 종류의 위젯 또는 데이터 그리드 구축을 시작 하면 나쁜 UX없이 2000 바인딩을 쉽게 칠 수 있습니다 .

예를 들어 사용 가능한 옵션을 필터링하기 위해 텍스트를 입력 할 수있는 콤보 상자를 고려하십시오. 이러한 종류의 컨트롤은 ~ 150 개의 아이템을 가질 수 있으며 여전히 유용합니다. 추가 기능 (예 : 현재 선택된 옵션의 특정 클래스)이있는 경우 옵션 당 3-5 개의 바인딩이 시작됩니다. 이 위젯 중 3 개를 한 페이지에 배치하십시오 (예 : 하나는 국가를 선택하고, 다른 하나는 해당 국가에서 도시를 선택하고 다른 하나는 호텔을 선택).

또는 회사 웹 응용 프로그램의 데이터 그리드를 고려하십시오. 페이지 당 50 개의 행은 불합리하지 않으며 각 행에는 10-20 개의 열이있을 수 있습니다. ng-repeats로 이것을 빌드하거나 일부 바인딩을 사용하는 일부 셀에 정보가있는 경우이 그리드만으로 2000 바인딩에 접근 할 수 있습니다.

AngularJS로 작업 할 때 이것이 문제라는 것을 알았습니다. 지금까지 내가 찾은 유일한 해결책은 ngOnce를 사용하지 않고 감시자와 유사한 트릭을 등록 취소하거나 구성하는 대신 양방향 바인딩을 사용하지 않고 위젯을 구성하는 것입니다. jQuery 및 DOM 조작으로 DOM을 빌드하는 지시문. 나는 이것이 Angular를 처음 사용하는 목적을 상실한다고 생각합니다.

나는 이것을 처리하는 다른 방법에 대한 제안을 듣고 싶지만 내 자신의 질문을 써야 할 수도 있습니다. 나는 이것을 의견에 넣고 싶었지만 너무 길다.

TL; DR
데이터 바인딩은 복잡한 페이지에서 성능 문제를 일으킬 수 있습니다.


26
네, 두 번째입니다. 우리의 앱의 주요 책임은 다른 엔티티 사이의 연결을 표시하는 것입니다. 주어진 페이지에는 10 개의 섹션이있을 수 있습니다. 각 섹션에는 테이블이 있습니다. 각 테이블에는 2-5 개의 자동 완성 필터가 있습니다. 각 테이블에는 2-5 개의 열이 있으며 각 열에는 10 개의 행이 있습니다. 우리는 매우 빠르게 퍼포먼스 문제를 겪고 "유사한 트릭"옵션을 사용합니다.
Scott Silvi

10
Angular는 데이터 바인딩에만 국한된 것이 아니며 일부 앱은 다른 앱이 인용 한 이유 때문에이 기능을 사용하고 싶지 않을 수도 있습니다. DI와 모듈성의 접근 방식은 그 자체로 많은 가치가 있다고 생각합니다. 매직 자동 바인딩을 사용하는 것은 좋지만 기존의 모든 구현에서는 성능이 저하됩니다. Angular의 방식은 대다수의 CRUD 웹 앱에 비해 우월한 것으로 나타 났으며 사람들은 극한의 상황을 극복하려고 노력하고 있습니다. 대체로 이벤트 리스닝 방법을 지원하는 것이 좋지만 단일 프레임 워크에는 기본적으로 너무 복잡 할 수 있습니까?
Jason Boyd

8
Angular는 이제이 문제를 해결하는 한 가지 방법과 한 번만 바인딩 데이터 바인딩이 있습니다. 또한 이제 repeater 소스에 대한 색인이 있으므로 전체 컨텐츠에 대한 DOM을 다시 작성하지 않고 목록을 수정할 수 있습니다.
Gaute Løken

6
@MW. 솔직히 나는 bind-once가 핵심이라고 생각했습니다. 그러나 그렇지 않은 것 같습니다. 자체 지시어를 작성할 때 할 수있는 일입니다. 기본적으로 지시하지 않고 물건을 연결합니다. 그러나 ux 모드가 있습니다 : github.com/pasvaz/bindonce
Gaute Løken

9
이 글을 읽는 모든 사람들에게 미래의 외침 : 한 번의 바인딩은 이제 Angular v1.3의 핵심 기능입니다. 여기에서 더 읽으십시오 : docs.angularjs.org/guide/expression
Nobita

158

더러워진 $scope개체 검사

Angular array$scope객체 에서 간단한 감시자를 유지 합니다. 당신이 어떤 검사하면 $scope당신은 그것이 포함 것을 발견 할 것이다 array라고 $$watchers.

각 감시자는 object다른 것들을 포함 하는

  1. 감시자가 모니터링하고있는 표현입니다. 이것은 단지 attribute이름이거나 더 복잡한 것일 수 있습니다 .
  2. 식의 마지막으로 알려진 값입니다. 이는 현재 계산 된 표현식 값과 비교하여 확인할 수 있습니다. 값이 다르면 감시자가 기능을 트리거하고 $scope더티로 표시합니다 .
  3. 감시자가 더러워지면 실행될 기능입니다.

감시자 정의 방법

AngularJS에서 감시자를 정의하는 방법에는 여러 가지가 있습니다.

  • 당신은 명시 적으로 할 수 에 .$watchattribute$scope

    $scope.$watch('person.username', validateUnique);
  • {{}}템플릿에 보간을 배치 할 수 있습니다 (현재에 감시자가 생성됩니다 $scope).

    <p>username: {{person.username}}</p>
  • ng-model감시자를 정의하는 것과 같은 지시문을 요청할 수 있습니다 .

    <input ng-model="person.username" />

그만큼 $digest사이클은 마지막 값에 대한 모든 관찰자를 확인

일반 채널 (ng-model, ng-repeat 등)을 통해 AngularJS와 상호 작용할 때 지시문에 의해 다이제스트주기가 트리거됩니다.

다이제스트주기는 모든 하위 요소 의 깊이 우선 순회입니다$scope . 각각 $scope object에 대해 반복하고 $$watchers array모든 표현식을 평가합니다. 새 표현식 값이 마지막으로 알려진 값과 다른 경우 감시자의 함수가 호출됩니다. 이 함수는 DOM의 일부를 다시 컴파일하고에 대한 값을 다시 계산하고 $scope를 트리거 AJAX request할 수 있습니다.

모든 범위가 순회되고 모든 시계 표현이 마지막 값에 대해 평가 및 확인됩니다.

감시자가 트리거되면 $scope더티

감시자가 트리거되면 앱이 변경된 것을 알고 앱이 $scope더티로 표시됩니다.

감시자 기능은 $scope부모 또는 다른 특성을 변경할 수 있습니다 $scope. 하나의 $watcher함수가 트리거 된 경우 다른 함수가 $scope여전히 깨끗한 지 보장 할 수 없으므로 전체 다이제스트주기를 다시 실행합니다.

AngularJS에는 양방향 바인딩이 있으므로 데이터를 $scope트리로 다시 전달할 수 있기 때문 입니다. $scope이미 소화 된 값을 더 높게 변경할 수 있습니다 . 아마도의 값을 변경했을 수 있습니다 $rootScope.

(가) 경우 $digest더러운, 우리는 전체 실행 $digest다시 사이클을

우리 $digest는 다이제스트 사이클이 깨끗해질 때까지 (모든 $watch표현식이 이전 사이클에서와 동일한 값을 갖거나) 다이제스트 한계에 도달 할 때까지 사이클을 계속 반복 합니다. 기본적으로이 제한은 10으로 설정되어 있습니다.

다이제스트 한계에 도달하면 AngularJS가 콘솔에서 오류를 발생시킵니다.

10 $digest() iterations reached. Aborting!

다이제스트는 기계에서는 어렵지만 개발자에게는 쉽습니다.

보시다시피 AngularJS 앱에서 무언가가 변경 될 때마다 AngularJS는 $scope계층 구조의 모든 단일 감시자 를 확인하여 응답 방법을 확인합니다. 개발자에게는 배선 코드를 거의 작성하지 않아도되기 때문에 생산성이 크게 향상됩니다. AngularJS는 값이 변경되었는지 확인하고 나머지 앱을 변경과 일치하게 만듭니다.

기계의 관점에서 볼 때 이것은 비효율적이며 너무 많은 감시자를 만들면 앱 속도가 느려집니다. Misko는 앱이 구형 브라우저에서 느리게 느껴지기 전에 약 4000 명의 감시자를 인용했습니다.

예를 들어이 제한은 ng-repeat큰 경우에 쉽게 도달 할 수 있습니다 JSON array. 감시자를 만들지 않고 템플릿을 컴파일하기 위해 일회용 바인딩과 같은 기능을 사용하여이 문제를 완화 할 수 있습니다.

너무 많은 감시자를 만드는 것을 피하는 방법

사용자가 앱과 상호 작용할 때마다 앱의 모든 단일 시청자가 한 번 이상 평가됩니다. AngularJS 앱 최적화의 큰 부분은 $scope트리 의 감시자 수를 줄이는 것 입니다. 이 작업을 수행하는 쉬운 방법 중 하나 는 한 번의 바인딩 입니다.

거의 변경되지 않는 데이터가있는 경우 :: 구문을 사용하여 한 번만 바인딩 할 수 있습니다.

<p>{{::person.username}}</p>

또는

<p ng-bind="::person.username"></p>

바인딩은 포함 템플릿이 렌더링되고 데이터가로드 될 때만 트리거됩니다. $scope .

ng-repeat항목이 많은 경우에 특히 중요 합니다.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>

감사합니다 @ user2864740-Misko의 답변이 최고가되어야합니다. 그는 프레임 워크를 누구보다 잘 알고 있으며, 스택 오버플로를 사용하는 것이 매우 좋습니다.
superluminary

4
나는 그 대답이 맨 위에 있어야한다는 데 동의하지 않는다. 무언가를 아는 것과 특정 질문에 대한 관련 / 세부 답변을 작성하는 것에는 차이가 있습니다. 영예를 얻는 더 좋은 방법이 있습니다. 어쨌든 ..
user2864740

1
나는 그것이 사실인지 의심하지 않지만 질문과 대답에 대한 질문 :)
user2864740 18

3
더티 체크의 작동 방식과 실제로 평가하는 내용에 대한 훌륭한 답변은 Misko의 답변에서 너무 명확하지 않았습니다.
strider

3
훌륭하고 자세한 답변. @ superluminary, 그러한 답변에 감사드립니다. 또한,이 답변을 읽은 후에, 우리는 비등 전성 표현을보고있는 표현으로 추가해서는 안된다는 점에 도달했습니다.
Mangu Singh Rajpurohit

81

이것이 나의 기본 이해입니다. 잘못되었을 수도 있습니다!

  1. 기능은 (보는 것을 반환) 기능을 전달하여 감시 $watch메소드에 .
  2. 감시 항목에 대한 변경은 $apply메소드에 의해 랩핑 된 코드 블록 내에서 이루어져야합니다 .
  3. 의 끝에 그들이 마지막 시간 이후 변경 있는지 확인하기 위해 시계와 각 검사를 통과하는 호출 방법을 달렸다.$apply$digest$digest
  4. 변경 사항이 발견되면 모든 변경 사항이 안정화 될 때까지 요약이 다시 호출됩니다.

정상적인 개발에서 HTML의 데이터 바인딩 구문은 AngularJS 컴파일러에게 시계를 만들도록 지시하고 컨트롤러 메서드는 $apply이미 내부에서 실행됩니다 . 따라서 응용 프로그램 개발자에게는 모두 투명합니다.


4
apply 메소드는 언제 트리거됩니까?
numan salati

3
@EliseuMonar 다이제스트 루프는 일부 이벤트 또는 $ apply () 호출의 결과로 실행되며 타이머를 기반으로 주기적으로 호출되지 않습니다. AngularJS의 $ watch 기능어떻게 작동합니까?를 참조하십시오 . 그리고 어떻게 바인딩 및 AngularJS와의 작업을 소화입니까?
adl

1
@ remi, AngularJS의 마지막 버전에 대해 걱정하지 않습니다. 그들은 이미 프록시 또는 Object.observe를 사용하고 있습니까? 그렇지 않은 경우 여전히 더티 검사 시대에 있으며, 이는 시간 제한 루프를 작성하여 모델 속성이 변경되었는지 확인합니다.
Eliseu Monar dos Santos

1
나는 다이제스트 10 배의 최대 실행 읽었습니다 sitepoint.com/understanding-angulars-apply-digest
user137717

62

나는 이것을 잠시 동안 궁금해했다. 세터없이 개체 AngularJS에 대한 알림이 어떻게 변경 $scope됩니까? 그것들을 폴링합니까?

실제로 수행하는 작업은 다음과 같습니다. 모델을 수정하는 "일반"장소는 이미 내장에서 AngularJS호출되었으므로 $apply코드 실행 후 자동으로 호출 됩니다. 컨트롤러 ng-click에 어떤 요소에 연결된 방법이 있다고 가정 해보십시오 . 때문에 AngularJS전선이 당신을 위해 그 방법을 함께의 호출, 그것은을 할 기회가 $apply적절한 위치에있다. 마찬가지로 뷰에 바로 나타나는 표현식의 경우 표현식이 실행 AngularJS되므로$apply .

문서가 외부의$apply 코드를 수동으로 호출 해야 한다는 이야기는 실행시 호출 스택 에서 발생하지 않는 코드에 관한 것입니다.AngularJSAngularJS


32

사진 설명 :

데이터 바인딩에는 매핑이 필요합니다

범위의 참조는 템플릿의 참조가 아닙니다. 두 개체를 데이터 바인딩 할 때는 첫 번째 개체를 듣고 다른 개체를 수정하는 세 번째 개체가 필요합니다.

여기에 이미지 설명을 입력하십시오

여기서를 수정 <input>하면 data-ref3 을 터치합니다 . 그리고 고전적인 데이터 바인딩 메커니즘data-ref4를 바꿀 것 입니다. 다른 {{data}}표현들은 어떻게 움직일까요?

이벤트는 $ digest ()로 이어진다

여기에 이미지 설명을 입력하십시오

각도는 유지 oldValue하고 newValue모든 바인딩의. 그리고 모든 Angular 이벤트 후에 유명한 $digest()루프는 WatchList를 검사하여 변경 사항이 있는지 확인합니다. 이 각도 이벤트가 되어 ng-click, ng-change, $http완료 ... $digest()의지 루프를 긴만큼 oldValue로부터 다르다newValue .

이전 그림에서 data-ref1 및 data-ref2가 변경되었음을 알 수 있습니다.

결론

계란과 닭고기와 조금 비슷합니다. 누가 시작하는지 알지 못하지만 대부분의 시간이 예상대로 작동하기를 바랍니다.

다른 점은 메모리와 CPU에 대한 간단한 바인딩의 영향을 쉽게 이해할 수 있다는 것입니다. 바라건대 데스크탑은 이것을 처리하기에 충분히 뚱뚱합니다. 휴대 전화는 그렇게 강력하지 않습니다.


22

분명히 Scope부착 된 객체에 변화가 있는지 정기적으로 점검하지 않습니다 . 범위에 연결된 모든 개체가 감시되는 것은 아닙니다. 스코프는 프로토 타입으로 $$ watchers를 유지합니다 . 이 호출 될 Scope때만이 과정을 반복합니다 .$$watchers$digest

Angular는 이들 각각에 대해 $$ watchers에 감시자를 추가합니다.

  1. {{expression}} — 템플릿 (및 표현식이있는 곳) 또는 ng-model을 정의 할 때.
  2. $ scope. $ watch ( 'expression / function') — JavaScript에서 앵귤러가 볼 범위 객체를 첨부 할 수 있습니다.

$ watch 함수는 세 가지 매개 변수를 사용합니다.

  1. 첫 번째는 객체를 반환하거나 표현식을 추가 할 수있는 감시자 함수입니다.

  2. 두 번째는 객체에 변경이있을 때 호출되는 리스너 함수입니다. DOM 변경과 같은 모든 것이이 함수에서 구현됩니다.

  3. 세 번째는 부울을 취하는 선택적 매개 변수입니다. true이면 angular deep은 객체를 감시하고 false 앵귤러는 객체에 대한 참조 감시 만 수행합니다. $ watch의 대략적인 구현은 다음과 같습니다

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

Angular에는 Digest Cycle이라는 흥미로운 것이 있습니다. $ scope. $ digest ()를 호출하면 $ digest주기가 시작됩니다. ng-click 지시문을 통해 핸들러 함수에서 $ scope 모델을 변경한다고 가정하십시오. 이 경우 AngularJS는 $ digest ()를 호출하여 $ digest주기를 자동으로 트리거합니다. $ 다이제스트주기를 자동으로 트리거합니다. $ digest의 대략적인 구현은 다음과 같습니다.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

JavaScript의 setTimeout () 함수를 사용하여 범위 모델을 업데이트하는 경우 Angular는 변경 내용을 알 수있는 방법이 없습니다. 이 경우 $ apply ()를 수동으로 호출하여 $ 다이제스트주기를 트리거하는 것은 우리의 책임입니다. 마찬가지로 DOM 이벤트 리스너를 설정하고 핸들러 함수 내에서 일부 모델을 변경하는 지시문이있는 경우 $ apply ()를 호출하여 변경 사항을 적용해야합니다. $ apply의 큰 아이디어는 Angular를 인식하지 못하는 코드를 실행할 수 있다는 것입니다. 그 코드는 여전히 범위의 내용을 변경할 수 있습니다. 해당 코드를 $ apply로 감싸면 $ digest () 호출이 처리됩니다. $ apply ()의 대략적인 구현.

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};

15

AngularJS는 $ watch () , $ digest ()$ apply () 의 세 가지 강력한 함수를 사용하여 데이터 바인딩 메커니즘을 처리합니다 . 대부분 AngularJS는 $ scope. $ watch () 및 $ scope. $ digest ()를 호출하지만 경우에 따라 새 값으로 업데이트하기 위해 이러한 함수를 수동으로 호출해야 할 수도 있습니다.

$ watch () :-

이 함수는 $ scope에서 변수의 변화를 관찰하는 데 사용됩니다. 여기에는 expression, listener 및 equality 객체의 세 가지 매개 변수가 사용됩니다. 여기서 listener 및 equality 객체는 선택적 매개 변수입니다.

$ digest () -

이 함수는 $ scope 객체의 모든 시계와 자식 $ scope 객체
(있는 경우)를 반복 합니다. $ digest ()가 시계를 반복 할 때 표현식의 값이 변경되었는지 확인합니다. 값이 변경된 경우 AngularJS는 새 값과 이전 값으로 리스너를 호출합니다. AngularJS가 필요하다고 생각할 때마다 $ digest () 함수가 호출됩니다. 예를 들어, 단추 클릭 후 또는 AJAX 호출 후. AngularJS가 $ digest () 함수를 호출하지 않는 경우가 있습니다. 이 경우 직접 호출해야합니다.

$ apply () -

Angular는 AngularJS 컨텍스트 내에있는 모델 변경 사항 만 자동으로 업데이트합니다. 브라우저 DOM 이벤트, setTimeout, XHR 또는 타사 라이브러리와 같이 Angular 컨텍스트 외부의 모델에서 변경을 수행하는 경우 $ apply ()를 수동으로 호출하여 변경 내용을 Angular에 알려야합니다. $ apply () 함수 호출이 AngularJS 호출 $ digest ()를 내부적으로 완료하면 모든 데이터 바인딩이 업데이트됩니다.


7

사람의 데이터 모델을 양식과 연결해야했는데, 내가 한 일은 데이터와 양식을 직접 매핑하는 것이 었습니다.

예를 들어 모델에 다음과 같은 것이 있다면

$scope.model.people.name

양식의 제어 입력 :

<input type="text" name="namePeople" model="model.people.name">

이렇게하면 객체 컨트롤러의 값을 수정하면 뷰에 자동으로 반영됩니다.

모델을 서버 데이터에서 업데이트 한 예는 작성된로드를 기반으로 우편 번호 및 우편 번호를 요청할 때 해당 뷰와 관련된 콜로니 및 도시 목록을 표시하고 기본적으로 사용자와 함께 첫 번째 값을 설정하는 것입니다. 그리고 이것은 매우 잘 작동했습니다. 무슨 일이 일어나는가에 따라 angularJS때로는 모델을 새로 고치는 데 몇 초가 걸리므로 데이터를 표시하는 동안 스피너를 넣을 수 있습니다.


14
나는이 답변을 5 번 읽었지만 여전히 여기서 의미하는 바를 이해하지 못합니다.
sbedulin

1
대답은 나를위한 퍼즐처럼 보인다
Aman

6
  1. 단방향 데이터 바인딩은 데이터 모델에서 값을 가져와 HTML 요소에 삽입하는 방식입니다. 뷰에서 모델을 업데이트 할 방법이 없습니다. 클래식 템플릿 시스템에서 사용됩니다. 이 시스템은 한 방향으로 만 데이터를 바인딩합니다.

  2. Angular 앱의 데이터 바인딩은 모델과 뷰 구성 요소 간의 데이터 자동 동기화입니다.

데이터 바인딩을 사용하면 모델을 응용 프로그램에서 단일 소스로 취급 할 수 있습니다. 뷰는 항상 모델의 투영입니다. 모델이 변경되면 뷰에 변경 사항이 반영되고 그 반대의 경우도 마찬가지입니다.


5

다음은 입력 필드를 사용하여 AngularJS와 데이터 바인딩하는 예입니다. 나중에 설명하겠습니다

HTML 코드

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

AngularJS 코드

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

위의 예에서 볼 수 있듯이 AngularJSng-modelHTML 요소, 특히 input필드 에서 발생하는 일을 듣고 감시하는 데 사용 합니다. 무언가가 발생하면 무언가를하십시오. 우리의 경우, ng-model콧수염 표기법을 사용하여 우리의 견해에 바인딩됩니다 {{}}. 입력 필드에 입력 한 내용이 화면에 즉시 표시됩니다. 이것이 AngularJS를 가장 간단한 형태로 사용하여 데이터 바인딩의 아름다움입니다.

도움이 되었기를 바랍니다.

Codepen 에 대한 실제 예제를 참조하십시오.


5

AngularJ는 양방향 데이터 바인딩을 지원합니다 .
데이터에 액세스 할 수 있음을 의미합니다. 보기-> 컨트롤러컨트롤러->보기

예를 들어.

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

다음 ng-model과 같이 데이터를 바인딩 할 수 있습니다 .-
2)

<input ng-model="name" />

<div> {{ name }} </div>

위의 예에서 사용자가 입력 할 내용이 있으면 <div>태그에 표시됩니다 .

html에서 컨트롤러로 입력을 바인딩하려면 :
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

name컨트롤러에서 입력을 사용하려면

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-model뷰를 바인딩하고 표현식으로 렌더링합니다 {{ }}.
ng-model보기에서 사용자에게 표시되고 사용자와 상호 작용하는 데이터입니다.
따라서 AngularJ에서 데이터를 쉽게 바인딩 할 수 있습니다.


4

Angular.js는 우리가 보는 모든 모델에 대해 감시자를 만듭니다. 모델이 변경 될 때마다 "ng-dirty"클래스가 모델에 적용되므로 감시자는 "ng-dirty"클래스가있는 모든 모델을 관찰하고 컨트롤러에서 값을 업데이트하거나 그 반대로 업데이트합니다.


3

데이터 바인딩:

데이터 바인딩이란 무엇입니까?

사용자가보기에서 데이터를 변경할 때마다 범위 모델에서 해당 변경 사항이 업데이트되고 그 반대도 마찬가지입니다.

그게 어떻게 가능해?

짧은 답변 : 다이제스트 사이클의 도움으로.

설명 : 각도 js는 감시자를 범위 모델에 설정하며, 모델에 변경이 있으면 리스너 기능을 시작합니다.

$scope.$watch('modelVar' , function(newValue,oldValue){

// 새로운 값을 가진 돔 업데이트 코드

});

그렇다면 감시자 함수는 언제 어떻게 호출됩니까?

감시자 기능은 다이제스트주기의 일부로 호출됩니다.

다이제스트 사이클은 ng-model, ng-bind, $ timeout, ng-click 등과 같은 지시문 / 서비스에 내장 된 각도 j의 일부로 자동 트리거됩니다. 다이제스트 사이클을 트리거 할 수 있습니다.

다이제스트 사이클 기능 :

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

$rootScope.$apply()

참고 : $ apply ()는 $ rootScope. $ digest ()와 동일합니다. 이는 더티 검사가 루트 또는 상단 또는 상위 범위에서 각도 js 애플리케이션의 모든 하위 $ scope까지 바로 시작됨을 의미합니다.

위의 기능은 응용 프로그램이 angular js 응용 프로그램인지 확인하여 언급 된 버전의 브라우저 IE에서도 작동합니다. 즉, 스크립트 태그에서 참조 된 angularjs 프레임 워크 스크립트 파일을 사용하고 있음을 의미합니다.

감사합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.