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


1956

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

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

이 작업을 수행 할 수있는 JavaScript 감시자가 있다는 것을 알았 습니다. 그러나 Internet Explorer 6 및 Internet 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)와 변경 리스너 ( KnockoutJS 및 Backbone.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
}]);

위의 예에서 볼 수 있듯이 AngularJS 는 ng-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.