toggle menu

[AngularJS] 쉽지만 쉽지않은 $timeout 서비스

2015. 1. 7. 13:58 AngularJS

들어가며


$timeout 서비스는window.setTimeout 을 사용하기 위한 Angular의 래퍼로, 대상이되는 함수(fn)는 자동적으로 try / catch 블록으로 처리되어  $exceptionHandler 서비스에서 에러를 컨트럴할 수 있게 된다.


timeout 함수를 등록했을 때의 promise 객체를 리턴하게 되는데, 이 promise는 timeout이 지정 시간에 도달하고 그 timeout 함수가 실행 될 때 resolve 된다.


window.setTimeout과는 달리 $timeout은 Promise 를 리턴하기 때문에 이전에 콜백으로 접근하는 방식의 코드가 아닌 promise 기반의 더 나은 코딩을 할 수 있는 장점이 있다. $timeout 의 첫번째 파라메터인 콜백 함수에서 값을 리턴하게 되면 이 값은 promise가 resolve 되었을 때 전달된다.






$timeout 서비스 사용방법


$timeout(fn [, delay ] [, invokeApply ]);


fn

지연 실행되어야 함수를 지정한다.


delay (optional)

지연시키는 시간을 밀리 초 단위로 지정하며 초기 값은 0이다.


invokeApply (optional)

만약 false로 설정하면 model dirty check를 생략하고, 그렇지 않으면 $apply 블록에서 fn을 실행한다.


리턴값

$timeout(fn [, delay ] [, invokeApply ]) 를 실행하면, Promise 객체를 리턴받게 된다. timeout이 지정 시간에 도달했을 때 resolve되는 Promise 로써, 이 promise가 resolve 될 경우, fn 함수의 반환 값을 반환한다.



$timeout.cancel(promise)

promise 관련 작업을 취소하는 메서드로, 이 메서드를 실행하면, promise는 reject 된다.

이 메서드 시행 시 $timeout 에 지정한 fn의 작업이 아직 실행되지 않고 취소에 성공했을 경우는 true를 돌려준다.


$timeout.flush()

테스트에서는 deferred 함수의 큐를 동시에 수행하기 위해 $ timeout.flush() 를 사용할 수 있다.


$timeout(function () {

	//지연된 작업이 여기에 위치한다.

	return 123; //리턴값 123은 promise의 resolve 콜백에 파라메터로 전달된다. 

}, 1000 /* 1000ms 뒤에 지연된 작업이 수행된다. */, true );





$timeout의 invokeApply 파라메터


$timeout 서비스의 세번째 파라메터인 invokeApply 에 대해서 더 깊이 파고들어 보자.

이 파라메터는 생략할 경우 기본값은 true로, false일 경우 AngularJS의 digest loops에서 model dirty check를 하지 않게 된다.


$timeout 서비스를 통해 수행하는 지연작업이 별도로 scope 내의 변수를 수정하지 않는 작업이라면, 굳이 model dirty check를 해서 부하를 증가시킬 필요는 없기 때문에 이 세번째 파라메터를 false 로 주면 성능 향상에 미미하게나마 도움이 될 것이다.


하지만 invokeApply 파라메터를 false로 줄 경우, AngularJS 1.0.x 버전의 경우 $timeout 의 Promise가 resolve 되지 않는 문제가 있다. 현재 최신 버전인 1.3.8 에서는 정상적으로 동작하지만, 이런 문제로 인해 invokeApply 파라메터를 사용할 때는 주의할 필요가 있다.


invokeApply를 true로 줄 경우 $rootScope에서 $apply() 를 해주기 때문에 이하 모든 child 스코프에도 모두 적용되게 된다.





AngularJS 표현식에서의 Promise


AngularJS의 표현식에서 Promise는 resolve 여부에 따라 아래와 같이 활용할 수 있다.


function promiseCtrl($scope, $timeout) { 
	$scope.result = $timeout(function({ 
		return "Ready!"; 
	}, 1000); 
}


<div ng-controller="promiseCtrl"> 
	{{result || "Preparing…"}}
</div> 





마치며


지금까지 AngularJS의 $timeout 서비스에 대해서 살펴보았다. window.setTimeout 의 래퍼 서비스에 가깝지만, 미묘한 차이점에 대해서 명확히 이해하지 못하면 실제 어플리케이션에서 예상하지 못한 결과를 만나기 쉽다. 실제로 invokeApply 파라메터를 수정하면서 예상과 다른 결과가 나와 이를 수정하기 위해 많은 고생을 하기도 했다.


$timeout은 setTimeout과 달리 Promise를 리턴한다는 것과, invokeApply 파라메터로 model dirty check 여부를 결정할 수 있다는 사실에 대해서 기억하고 AngularJS 어플리케이션을 개발할 수 있기를 기대한다.



AngularJS 관련 포스팅 더보기