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.