AngularJS에서 $ scope. $ watch 및 $ scope. $ apply를 어떻게 사용합니까?


1088

내가 사용하는 방법을 이해하지 않습니다 $scope.$watch$scope.$apply. 공식 문서는 도움이되지 않습니다.

내가 구체적으로 이해하지 못하는 것 :

  • 그들은 DOM에 연결되어 있습니까?
  • 모델의 DOM 변경을 어떻게 업데이트합니까?
  • 그들 사이의 연결점은 무엇입니까?

이 튜토리얼을 시도했지만 이해 $watch하고 $apply당연합니다.

무엇을 $apply하고 $watch어떻게, 그리고 그들을 적절하게 어떻게 사용합니까?

답변:


1737

AngularJS를 이해하려면 작동 방식에 대해 알고 있어야합니다.

다이제스트주기 및 $ scope

무엇보다도 AngularJS는 소위 다이제스트 사이클 의 개념을 정의합니다 . 이주기는 루프로 간주 될 수 있으며,이 과정에서 AngularJS는 모든 변수가 감시 하는 모든 변수에 변경 사항이 있는지 확인합니다 $scope. 따라서 $scope.myVar컨트롤러에서 정의 하고이 변수가 감시 대상으로 표시된myVar 경우 루프의 각 반복에서 변경 사항을 모니터링하도록 AngularJS에 암시 적으로 지시 합니다.

자연스러운 후속 질문은 다음과 같습니다. 모든 것이 $scope감시 대상입니까? 다행히도 의 모든 객체에 대한 변경 사항을 관찰하려면 $scope요약 루프가 평가하는 데 시간이 오래 걸리고 성능 문제가 빠르게 발생합니다. 이것이 AngularJS 팀이 $scope변수를 감시하는 것으로 선언하는 두 가지 방법을 제공 한 이유입니다 (아래 참조).

$ watch는 $ scope 변경을 듣는 데 도움이됩니다.

$scope변수를 감시하는 것으로 선언하는 두 가지 방법이 있습니다 .

  1. 표현식을 통해 템플리트에서이를 사용하여 <span>{{myVar}}</span>
  2. $watch서비스 를 통해 수동으로 추가

광고 1) 가장 일반적인 시나리오이며 이전에 본 적이 있지만 이것이 백그라운드에서 시계를 만들었다는 것을 몰랐습니다. 그렇습니다! AngularJS 지시문 (예 :)을 사용하면 ng-repeat암시 적 시계를 만들 수도 있습니다.

광고 2) 자신 만의 시계 를 만드는 방법 입니다. $watch서비스 $scope는에 연결된 일부 값 이 변경 되었을 때 일부 코드를 실행하는 데 도움이됩니다 . 거의 사용되지 않지만 때때로 도움이됩니다. 예를 들어, 'myVar'가 변경 될 때마다 일부 코드를 실행하려는 경우 다음을 수행 할 수 있습니다.

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

$ apply는 다이제스트 사이클과 변경 사항을 통합 할 수 있습니다

$apply함수를 통합 메커니즘으로 생각할 수 있습니다 . 객체에 직접 연결된$scope 일부 감시 변수 를 변경할 때마다 AngularJS는 변경이 발생했음을 알게됩니다. AngularJS는 이러한 변경 사항을 모니터링하는 것을 이미 알고 있기 때문입니다. 따라서 프레임 워크가 관리하는 코드에서 발생하면 다이제스트주기가 계속됩니다.

그러나 때로는 AngularJS 세계 외부의 일부 값변경 하고 변경 사항이 정상적으로 전파되는 것을보고 싶을 때가 있습니다 . 이것을 고려하십시오 $scope.myVar-jQuery의 $.ajax()핸들러 내에서 수정 될 값이 있습니다 . 이것은 미래에 일어날 것입니다. AngularJS는 jQuery를 기다리도록 지시받지 않았기 때문에 이것이 일어날 때까지 기다릴 수 없습니다.

이를 해결하기 위해 $apply소개되었습니다. 다이제스트 사이클을 명시 적으로 시작할 수 있습니다. 그러나 일부 데이터를 AngularJS (다른 프레임 워크와의 통합)로 마이그레이션하는 데만 사용해야하지만 AngularJS는 오류를 발생시키기 때문에이 방법을 일반 AngularJS 코드와 결합하여 사용하지 마십시오.

이 모든 것이 DOM과 어떤 관련이 있습니까?

글쎄, 당신은 실제로 튜토리얼을 다시 따라야합니다. 이제 모든 것을 알았습니다. 다이제스트주기는 $scope변경 사항이없는 한 모든 감시자에 연결된 모든 감시자를 평가하여 UI와 JavaScript 코드가 동기화 된 상태를 유지하도록합니다 . 다이제스트 루프에서 더 이상 변경이 발생하지 않으면 완료된 것으로 간주됩니다.

$scopeController에서 개체를 명시 적으로 또는 {{expression}}보기에서 직접 형식 으로 선언 하여 개체에 연결할 수 있습니다 .

이 모든 것에 대한 기본 지식을 명확히하는 데 도움이되기를 바랍니다.

추가 자료 :


57
"각도는 모든 $ scopes에 부착 된 모든 변수에 변화가 있는지 확인합니다"-나는 그것이 옳다고 생각하지 않습니다. Angular 전용 (더러운)은 $ watches가 설정된 $ scope 속성을 확인한다고 생각합니다 (보기에서 {{}}을 사용하면 $ watch가 자동으로 생성됩니다). 범위 페이지의 "Scope $ watch 성능 고려 사항"섹션도 참조 하십시오 .
Mark Rajcok

5
그럴 수도 있습니다. 그것에 대해 더 많이 읽고 내 답변을 편집 할 시간을 찾으려고 노력할 것입니다.
ŁukaszBachman

15
@MarkRajcok, 네 말이 맞아. 답장을 변경하고 이것이 어떻게 구현되는지 잘 보여주는 기사를 지적했습니다.
ŁukaszBachman

3
이것을 사용하는 것은 어떻습니까? ( "Control as"방법)
Leandro

2
"다른 이름으로 제어"를 사용해도 위 정보에 영향을 미치지 않아야합니다. this.myVar를 사용하면 myVar이 범위에 놓입니다.
Marcus Rådell

161

AngularJS에서는 모델을 업데이트하고 뷰 / 템플릿은 DOM을 "자동으로"(내장 또는 사용자 지정 지시문을 통해) 업데이트합니다.

Scope 메소드 인 $ apply 및 $ watch는 DOM과 관련이 없습니다.

개념 페이지 (섹션 "런타임")는 $ 소화 루프의 꽤 좋은 설명, $ 적용하는 $ evalAsync 큐와 $ 시계 목록이 있습니다. 텍스트와 함께 제공되는 그림은 다음과 같습니다.

$ 다이제스트 루프

범위에 액세스 할 수있는 코드 (일반적으로 컨트롤러 및 지시문 (그들의 링크 함수 및 / 또는 해당 컨트롤러)) 는 AngularJS가 해당 범위에 대해 평가할 " watchExpression "을 설정할 수 있습니다 . 이 평가는 AngularJS가 $ digest 루프 (특히 "$ watch list"루프)에 들어갈 때마다 발생합니다. 개별 스코프 속성을 볼 수 있고, 두 속성을 함께 볼 수있는 함수를 정의하고, 배열의 길이 등을 볼 수 있습니다.

상황이 "AngularJS 내부에서"발생하는 경우 – 예를 들어 AngularJS 양방향 데이터 바인딩이 활성화 된 텍스트 상자에 입력 (예 : ng-model 사용), $ http 콜백 발생 등 – $ apply가 이미 호출되었으므로 위 그림의 "AngularJS"사각형 안에 있습니다. 모든 watchExpression이 평가됩니다 (추가 변경이 감지되지 않을 때까지 두 번 이상 가능).

예를 들어 지시문에서 bind ()를 사용한 다음 이벤트가 발생하여 콜백이 발생하거나 jQuery에 등록 된 콜백이 발생하는 등 AngularJS 외부에서 상황이 발생하면 여전히 "기본"사각형에있게됩니다. 콜백 코드가 $ watch가보고있는 것을 수정하면 $ apply를 호출하여 AngularJS 사각형으로 들어가서 $ digest 루프가 실행되므로 AngularJS는 변경 사항을 확인하고 그 마법을 수행합니다.


5
나는 아이디어를 이해하지만, 내가 이해하지 못하는 것은 데이터가 실제로 어떻게 전송되는지입니다. 많은 데이터가있는 객체 인 모델이 있습니다. 일부 모델을 사용하여 DOM을 조작합니다. 그런 다음 일부가 변경됩니다. 변경된 데이터를 모델의 올바른 위치에 배치하려면 어떻게합니까? 내가 사용한 예에서 그는 조작을하고 결국 단순히을 사용합니다 scope.$apply(scope.model). 어떤 데이터가 전송되는지 이해하고 모델의 올바른 위치로 어떻게 전송됩니까?
ilyo

6
마법의 데이터 전송이 발생하지 않습니다. 일반적으로 Angular 앱에서는 Angular 모델을 변경 한 다음 뷰 / DOM 업데이트를 수행해야합니다. Angular 외부에서 DOM을 업데이트하는 경우 모델을 수동으로 업데이트해야합니다. scope.$apply(scope.model)간단히 scope.modelAngular 표현식으로 평가 한 다음 $ digest 루프를 입력하십시오. 참조하는 기사 scope.$apply()에서 모델은 이미 $ watch'ed이므로 충분할 것입니다. stop () 함수가 모델을 업데이트 중입니다 (toUpdate는 scope.model에 대한 참조라고 생각합니다), $ apply가 호출됩니다.
Mark Rajcok

AngularJS 문서 가이 답변 아래에서 벗어난 것처럼 보입니다 (첫 번째 링크에는 "런타임"이 없거나 $watch페이지에 있고 두 번째 링크는 어쨌든 끊어졌습니다). 고통스럽게도, 아카이브 버전 은 비동기 프로세스가 내용을 만든 것을 캐시하지 않았습니다.
ruffin

52

AngularJS는이 events-loop을 확장하여 이라는 것을 만듭니다 AngularJS context.

$ watch ()

UI에서 무언가를 바인딩 할 때마다 목록 $watch에 a$watch 를 삽입 합니다 .

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

여기 $scope.user에 첫 번째 입력에 바인딩되어 있고 두 번째 입력에 $scope.pass바인딩되어 있습니다. 이렇게하면 목록에 두 개의 $watches$watch 가 추가 됩니다 .

우리의 경우 템플릿이 로드, 일명 연결 단계에서, 컴파일러는 모든 지시를 찾아 모든 생성 할 $watch필요 말이지.

AngularJS와는 제공 $watch, $watchcollection$watch(true). 아래는 감시자 로부터 얻은 세 가지를 모두 자세히 설명하는 깔끔한 다이어그램 입니다.

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

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digest 고리

브라우저가 AngularJS 컨텍스트에서 관리 할 수있는 이벤트를 수신하면 $digest루프가 시작됩니다. 이 루프는 두 개의 작은 루프로 구성됩니다. 하나는 $evalAsync대기열을 처리하고 다른 하나 는 대기열을 처리합니다 $watch list. $digest의 목록을 의지 루프 $watch우리가 가지고

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

$watchng-click은 시계를 만들지 않기 때문에 여기에는 하나만 있습니다.

우리는 버튼을 누릅니다.

  1. 브라우저는 AngularJS 컨텍스트로 들어갈 이벤트를받습니다.
  2. $digest루프가 실행됩니다 및 변경에 대한 모든 $ 시계를 요청합니다.
  3. 부터 $watch$ scope.name의 변화를 지켜보고 된이 변화를보고, 그것은 또 다른 강제 $digest루프.
  4. 새로운 루프는 아무 것도보고하지 않습니다.
  5. 브라우저는 제어권을 다시 얻고 $ scope.name의 새로운 값을 반영하여 DOM을 업데이트합니다.
  6. 여기서 중요한 것은 AngularJS 컨텍스트에 들어가는 모든 이벤트가 $digest루프 를 실행한다는 것 입니다. 즉, 입력에 문자를 쓸 때마다 루프 $watch가이 페이지의 모든 항목 을 검사 합니다.

$ apply ()

$apply이벤트가 시작될 때 전화를 걸면 각도 컨텍스트를 통과하지만 전화를 걸지 않으면 외부에서 실행됩니다. 그렇게 쉽습니다. 내부적으로 루프 $apply를 호출하고$digest() DOM이 새로 업데이트 된 값으로 업데이트되도록 모든 시계를 반복합니다.

$apply()방법은 전체 $scope체인 에서 감시자를 트리거 하는 반면 $digest(), 현재 $scope및 그 감시자 만 트리거 합니다 children. 상위 $scope개체가 로컬 변경 사항에 대해 알 필요가없는 경우을 사용할 수 있습니다 $digest().


18

나는 어떤 커버 매우 깊이있는 영상을 발견 $watch, $apply, $digest과에 사이클을 소화 :

다음은 해당 비디오에서 개념을 설명하기 위해 사용되는 두 개의 슬라이드입니다 (위의 링크가 제거되거나 작동하지 않는 경우에 대비).

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

위 이미지에서 "$ scope.c"는 데이터 바인딩 (마크 업)에 사용되지 않으므로 감시되지 않습니다. 다른 두 개 ( $scope.a$scope.b)가 감시됩니다.

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

위의 이미지에서 : AngularJS는 해당 브라우저 이벤트를 기반으로 이벤트를 캡처하고 다이제스트주기를 수행하고 (변경 사항이있는 모든 시계를 통과) 시계 기능을 실행하고 DOM을 업데이트합니다. 그렇지 않으면 브라우저 이벤트는, 다이제스트주기는 수동으로 사용하여 트리거 할 수 있습니다 $apply또는 $digest.

에 대한 자세한 $apply$digest:

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


17

있다 $watchGroup$watchCollection뿐만 아니라. 특히, $watchGroupdom 객체가 아닌 뷰에 여러 속성이있는 객체를 업데이트하는 함수 (예 : canvas의 다른 뷰, WebGL 또는 서버 요청) 를 업데이트하려는 경우 실제로 유용합니다 .

여기에 문서 링크가 있습니다.


나는 그것에 대해 논평했을 것입니다. $watchCollection그러나 나는 당신이 이미 한 것을 보았습니다. 다음은 AngularJS 사이트에서 이에 대한 설명서 입니다. 그들은 $watch깊이에 대한 아주 좋은 시각을 제공합니다 . 정보는 페이지 하단에 가깝습니다.
JabberwockyDecompiler

15

위의 모든 내용을 읽은 후 지루하고 졸리십시오 (죄송하지만 사실입니다). 매우 기술적이고 깊이 있고 상세하며 건조합니다. 내가 왜 쓰는거야? AngularJS는 방대하기 때문에 많은 상호 연결된 개념으로 인해 누구나 쉽게 갈 수 있습니다. 나는 종종 나 자신에게 물었다. 나는 그들을 이해할만큼 똑똑하지 않은가? 아니! 모든 용어 없이 기술을 설명 할 수있는 사람은 거의 없기 때문입니다 ! 알겠습니다.

1) 그것들은 모두 이벤트 중심의 것입니다. (웃음은 들었지만 계속 읽습니다)

이벤트 중심이 무엇인지 모른다면 페이지에 단추를 놓은 다음 "온 클릭"기능을 사용하여 단추를 클릭하고 사용자가 단추를 클릭하여 함수. 또는 SQL Server / Oracle의 "트리거"를 생각하십시오.

2) $ watch는 "클릭시"입니다.

특별한 점은 두 가지 기능을 매개 변수로 사용한다는 것입니다. 첫 번째는 이벤트에서 값을 제공하고 두 번째는 값을 고려합니다 ...

3) $ digest는 지칠 줄 모르고 주위를 점검 하는 보스입니다.

4) $ apply는 실패 방지와 같이 수동으로 수행 할 때 방법을 제공합니다 (클릭시 킥이 발생하지 않으면 강제로 실행).

이제 시각적으로 만들어 봅시다. 아이디어를 더 쉽게 잡을 수 있도록 이것을 묘사하십시오.

레스토랑 안에,

-웨이터

고객으로부터 주문을 받아야합니다.

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- MANAGER 확인 모든 웨이터가 고객의 변화의 징후에 반응, 깨어하게 돌아 다니고. 이것은$digest()

-OWNER 는 요청에 따라 모든 사람을 운전할 수있는 최고의 힘을 가지고 있습니다.$apply()


2
이것은 5 살짜리가 이해할 수 있습니다. 이런 종류의 답변에 감사드립니다. +1
Chris22
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.