AngularJS (이하 Angular)는 Two-way
binding이라는 편리한 기능을 제공하지만 이 기능을 사용할 때 몇 가지 어려운 점이 있습니다. 그 중에 하나가 Angular Context 외에서 들어오는 데이터를 모델에 업데이트를 할
때 (여기서 모델이란 $scope로 정의된 variable들을 이야기합니다. 예: $scope.data) 개발자가
인위적으로 업데이트를 해야하며 이 때 사용하는 것이 $digest, $apply, $timeout 또는 $evalAsync
입니다. 참고로 Angular Context외 (또는 Angular Scope 외)란 Angular를 사용하지 않고 제작하는 모듈을 가리키며 가장 간단한 예로 서버를 들 수 있습니다. 서버에서
어떤 이벤트가 발생해서 Angular로 제작된 클라이언트 모듈 쪽으로 데이터가 들어오고 그 들어온 데이터를
UI에 반영하기 위해서 $scope.data에 업데이트를 해야 하는데
위에 언급한 함수들을 사용하지 않으면 클라이언트 모듈 쪽에는 데이터가 업데이트 되었지만 UI쪽인 HTML
쪽에는 (보통 {{data}} 형식으로 포함된)
업데이트가 되지 않아서 UI에 반영이 되지 않은채로 남아있습니다.
Two-way binding의
동작 원리
Two-way binding의
동작원리는 개발자가 $scope를 이용해서 variable을 생성하면
생성된 variable 에 watcher가 생성되고 $apply()나 $digest()가 실행되었을 때 현재까지 생성된 모든 watcher들이 실행되어서 변화된 값을 업데이트합니다. 여기서 watcher란 할당된 variable의 old value랑 new
value를 비교하여 두 값이 다를 경우 old value를 new
value로 업데이트해주는 모듈로 $scope.$watch 함수를 이용하여 이 작업을
합니다. UI쪽에서 발생하는 데이터값의 변화에 Two-way binding이 아무런 추가 작업 없이 정상 동작하는 이유는 Angular가 UI에서 발생하는 이벤트에 대해 $apply()를 자동으로 실행하기 때문입니다.
예를 들어 ng-click 같은 이벤트가 생성이 된다면 $apply()도 자동으로 실행이 됩니다.
$digest()
$digest()는 위의 동작원리에서
설명한 대로 현재까지 생성된 모든 $scope variable 들의 watcher를 실행하여 값이 변화된 variable의 값을 최신값으로 업데이트해주는 일을 합니다.
사용 예: $scope.digest();
$apply()
간단하게 설명하면 $apply()는 $rootScope.$digest()랑 같습니다. 하는 일은 $digest()와 같지만 다른
점은 커버하는 scope가 다르다는 점입니다. 다시 말해서
$digest()는 해당 scope의 variable의 값들만 업데이트하지만 $apply()는 무조건 rootScope와 rootScope 밑에 있는 모든 child scope들의 variable들 값을 모두 업데이트하기 때문에 자주 사용하면 제품 전체의 성능/효율성을 저하 시킬 수 있습니다. 기본적으로 Angular는 $apply()의 사용을 추천하고 있지만 제 개인적인 의견으로는 만약 어떤 scope의 variable이 업데이트 되어야 하는지 안다면 $digest()의 사용을 추천합니다.
사용 예: $scope.$apply(); 또는 $scope.$apply(function()
{ ….. } );
$timeout()
$timeout()은 일반적인
자바스크립의 API인 setTimeout()의 Angular
버전으로 $timeout()함수 안에서 바뀐 variable 값을 업데이트하기 위해 $apply()를 기본적으로 포함하고 있습니다.
$timeout()은 보통 setTimeout()과 마찬가지로 얼마동안의 Delay
이후에 해당 코드를 실행하기 위해 사용되어지고 있는데 이 용도 이외에 ‘$digest already in
progress’ 에러 발생에 대한 임시 해결책으로도 사용되어지고 있습니다. (한
Directive나 Controller 안에서 여러 번의 $apply()를 포함한 개발을 해본 개발자라면 최소한 한 번 이상은 저 에러 메세지를 본 경험이 있을겁니다.)
‘$digest already in progress’에러의 발생원인은 Angular는 기본적으로 한 번에 두 개의 $digest() 동시 실행을 금지하고 있어서 이미 $digest()가 실행 중일 때 또 다른 $digest()가 실행이 된다면 이 에러 메세지가 출력되고 나중에
실행된 $digest()는 실행이 되지 않습니다. 그럼 어떻게 $timeout()의 사용이 이 문제의 해결책이 될 수 있는건가요? 그 이유는 $timeout()의 $apply() 실행 타이밍 때문인데 $timeout()은 이미 기존에 실행되고 있는 $digest()가 있다면 그 실행이 끝날 때까지 기다렸다가
$timeout() 내부에 포함된 $scope.$apply()을 실행하는
특징이 있고 이 때문에 위의 에러에 대한 임시 해결책으로 사용되어 지고 있습니다.
사용 예: $timeout(function() {…….}, 0);
$evalAsync()
$evalAsync()는 ‘$digest
already in progress’에러에 대한 Angular팀의 근본적인 해결책으로
이해하시면 편합니다. (위에도 언급했듯이 $timeout()의 기본용도는
이 문제의 해결이 아닌 얼마간의 Delay이후에 실행이기 때문에 근본적인 해결책이 될 수는 없습니다.
또한 약간의 화면 깜빡이는 문제를 발생시킬 수도 있습니다.) $evalAsync()도 기본적으로 $apply() 함수를 포함하고 있으며 현재 진행중인 $digest()가 있을 경우에 이 $digest()의 실행이 끝나기 전에 $evalAsync()에 포함된 variable의 바뀐 데이터도 같이 업데이트할 수 있는 기능을 제공합니다.
$evalAsync()는 AngularJS 1.2 버전부터 제공되어지고 있습니다.
사용 예: $scope.$evalAsync(function() {…….});
추가사항:
AngularJS 1.3 버전부터
$applyAsync() 함수가 추가 되었다고 합니다. 기본적인 기능은 $evalAsync()와 비슷하지만 효율성 면에서 아주 미세한 차이가 있다고 하는 것 같은데 필자는 사용 경험이 없어서 자세한 사항은 잘 모르겠습니다.
References
Good content. You write beautiful things.
ReplyDeletetaksi
mrbahis
sportsbet
vbet
korsan taksi
vbet
mrbahis
sportsbet
hacklink
Good text Write good content success. Thank you
ReplyDeletepoker siteleri
bonus veren siteler
betpark
betmatik
tipobet
kibris bahis siteleri
mobil ödeme bahis
kralbet
hatay
ReplyDeletekars
mardin
samsun
urfa
ESVFV
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
İOGV
شركة تنظيف مكيفات بالاحساء
ReplyDeleteصيانة مكيفات الاحساء
شركة تنظيف منازل بجازان cwnlNPX4LE
ReplyDelete