2013 년 10 월 9 일 업데이트 : 실행 루프의 대화 형 시각화를 확인하십시오. https://machty.s3.amazonaws.com/ember-run-loop-visual/index.html
2013 년 5 월 9 일 업데이트 : 아래의 모든 기본 개념은 여전히 최신 상태이지만 이 커밋 시점 에서 Ember Run Loop 구현은 매우 사소한 API 차이가있는 backburner.js 라는 별도의 라이브러리로 분리되었습니다 .
먼저 다음을 읽으십시오.
http://blog.sproutcore.com/the-run-loop-part-1/
http://blog.sproutcore.com/the-run-loop-part-2/
Ember에게 100 % 정확하지는 않지만 RunLoop의 핵심 개념과 동기는 여전히 일반적으로 Ember에 적용됩니다. 일부 구현 세부 정보 만 다릅니다. 그러나 귀하의 질문에 대해 :
Ember RunLoop은 언제 시작됩니다. 라우터, 뷰 또는 컨트롤러 또는 다른 것에 의존합니까?
모든 기본 사용자 이벤트 (예 : 키보드 이벤트, 마우스 이벤트 등)는 런 루프를 발생시킵니다. 이를 통해 캡처 된 (마우스 / 키보드 / 타이머 / 기타) 이벤트에 의해 바인딩 된 속성에 대한 변경 사항이 시스템에 제어권을 다시 반환하기 전에 Ember의 데이터 바인딩 시스템 전체에 완전히 전파됩니다. 따라서 마우스 이동, 키 누르기, 버튼 클릭 등은 모두 런 루프를 시작합니다.
대략 얼마나 걸립니까?
어떤 시점에서도 RunLoop은 시스템을 통해 모든 변경 사항을 전파하고 최대 시간 제한에 도달 한 후 RunLoop을 중지하는 데 걸리는 시간을 추적하지 않습니다. 오히려 RunLoop 항상 완료 될 때까지 실행되며, 모든 만료 된 타이머가 호출 될 때까지 멈추지 않을 것입니다, 바인딩 전파, 그리고 아마도 자신의 바인딩 등 전파. 분명히 단일 이벤트에서 전파해야하는 변경 사항이 많을수록 RunLoop이 완료되는 데 더 오래 걸립니다. 다음은 RunLoop이 실행 루프가없는 다른 프레임 워크 (Backbone)에 비해 변경 사항 전파로 인해 RunLoop이 수렁에 빠질 수있는 방법에 대한 (매우 불공평 한) 예입니다 : http://jsfiddle.net/jashkenas/CGSd5/. 이야기의 도덕 : RunLoop은 Ember에서하고 싶은 대부분의 작업에 대해 정말 빠르며 Ember의 강력한 힘이있는 곳입니다.하지만 자바 스크립트로 30 개의 원을 초당 60 프레임으로 애니메이션하고 싶다면 Ember의 RunLoop에 의존하는 것보다 더 나은 방법 일 수 있습니다.
RunLoop이 항상 실행되고 있는지 아니면 실행 시작부터 끝까지의 기간을 나타내는 것일뿐 일정 시간 동안 실행되지 않을 수 있습니다.
항상 실행되지 않습니다 -이 말에서 다르다, 실행 루프를 A가 들어있는 서버에 - 그것은 어떤 점에서 또는 다른 앱을 중지 할 시스템에 대한 제어 등을 반환하는 while(true)
때까지 무한대에 간다 서버는 종료 신호를받습니다. Ember RunLoop에는 그런 while(true)
것이 없지만 사용자 / 타이머 이벤트에 대한 응답으로 만 작동됩니다.
하나의 RunLoop 내에서 뷰가 생성되는 경우 루프가 종료 될 때 모든 콘텐츠가 DOM으로 들어가는 것이 보장됩니까?
우리가 그것을 알아낼 수 있는지 봅시다. SC에서 Ember RunLoop으로의 큰 변화 중 하나는 (SproutCore의 RL에 대한 첫 번째 링크의 다이어그램에서 볼 수있는) invokeOnce
와 사이를 앞뒤로 반복하는 대신 invokeLast
Ember가 '대기열'목록을 제공한다는 것입니다. 실행 루프가 진행되는 동안 작업이 속한 대기열을 지정하여 작업 (실행 루프 중에 호출되는 함수)을 예약 할 수 있습니다 (출처 :) Ember.run.scheduleOnce('render', bindView, 'rerender');
.
당신이 보면 run_loop.js
소스 코드에서, 당신은 볼 Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
당신이 엠버 응용 프로그램의 브라우저에서 자바 스크립트 디버거를 열고 평가 아직 있다면, Ember.run.queues
당신은 큐의보다 완전한 목록을 얻을 : ["sync", "actions", "render", "afterRender", "destroy", "timers"]
. Ember는 코드베이스를 매우 모듈 식으로 유지하며, 라이브러리의 별도 부분에있는 자체 코드뿐만 아니라 더 많은 대기열을 삽입 할 수 있도록합니다. 이 경우 Ember Views 라이브러리 는 특히 대기열 뒤에 삽입 render
하고 afterRender
대기열에 넣습니다 actions
. 그 이유를 곧 알게 될 것입니다. 첫째, RunLoop 알고리즘 :
RunLoop 알고리즘은 위의 SC 실행 루프 문서에서 설명한 것과 거의 같습니다.
- 당신은 RunLoop 사이에 코드를 실행
.begin()
하고 .end()
, 단지 엠버에서 대신 내에서 코드를 실행할 수 있습니다 Ember.run
내부적으로 호출 할 것이다, begin
그리고 end
당신을. (Ember 코드베이스의 내부 실행 루프 코드 만 여전히 begin
및을 사용하므로을 계속 end
사용해야합니다. Ember.run
)
end()
이 호출 된 후 RunLoop은 Ember.run
함수에 전달 된 코드 덩어리에 의해 만들어진 모든 단일 변경 사항을 전파하기 위해 작동합니다. 여기에는 바인딩 된 속성의 값 전파, DOM에 대한 뷰 변경 렌더링 등이 포함됩니다. 이러한 작업 (바인딩, DOM 요소 렌더링 등)이 수행되는 순서는 Ember.run.queues
위에서 설명한 배열에 의해 결정됩니다 .
- 실행 루프는 첫 번째 대기열 인
sync
. 코드에 sync
의해 대기열에 예약 된 모든 작업을 실행합니다 Ember.run
. 이러한 작업은 동일한 RunLoop 동안 수행 할 더 많은 작업을 자체적으로 예약 할 수 있으며, 모든 대기열이 플러시 될 때까지 모든 작업을 수행하도록하는 것은 RunLoop의 몫입니다. 이 작업을 수행하는 방법은 모든 대기열의 끝에서 RunLoop이 이전에 플러시 된 모든 대기열을 살펴보고 새 작업이 예약되었는지 확인하는 것입니다. 그렇다면, 수행되지 않은 예약 된 작업으로 가장 빠른 대기열의 시작 부분에서 시작하고 대기열을 플러시하고 단계를 계속 추적하고 모든 대기열이 완전히 비워 질 때까지 필요할 때 다시 시작해야합니다.
이것이 알고리즘의 본질입니다. 이것이 바인딩 된 데이터가 앱을 통해 전파되는 방법입니다. RunLoop이 완료 될 때까지 실행되면 바인딩 된 모든 데이터가 완전히 전파 될 것으로 예상 할 수 있습니다. 그렇다면 DOM 요소는 어떻습니까?
Ember Views 라이브러리에 추가 된 대기열을 포함하여 대기열의 순서는 여기에서 중요합니다. 통지 render
및 afterRender
후 올 sync
하고 action
. sync
큐가 결합 된 데이터를 전파하기위한 모든 조치를 포함합니다. ( action
그 후에는 Ember 소스에서 드물게 사용됩니다). 위의 알고리즘을 기반으로 RunLoop이 render
큐에 도달 할 때 까지 모든 데이터 바인딩이 동기화를 완료 할 것입니다. 이것은 의도적으로 설계된 것입니다. 전에 DOM 요소를 렌더링하는 값 비싼 작업을 수행하고 싶지 않을 것입니다.데이터 바인딩을 동기화하려면 업데이트 된 데이터로 DOM 요소를 다시 렌더링해야 할 가능성이 높기 때문에 모든 RunLoop 큐를 비우는 매우 비효율적이고 오류가 발생하기 쉬운 방법입니다. 따라서 Ember는 render
대기열 에서 DOM 요소를 렌더링하기 전에 가능한 모든 데이터 바인딩 작업을 지능적으로 처리합니다 .
따라서 마지막으로 질문에 대답하기 위해 예, 필요한 DOM 렌더링이 시간 Ember.run
이 끝날 때까지 수행 될 것으로 예상 할 수 있습니다 . 다음은 시연 할 jsFiddle입니다. http://jsfiddle.net/machty/6p6XJ/328/
RunLoop에 대해 알아야 할 기타 사항
관찰자 대 바인딩
관찰자 및 바인딩은 "감시 된"속성의 변경 사항에 응답하는 유사한 기능을 갖지만 RunLoop의 컨텍스트에서 완전히 다르게 작동한다는 점에 유의해야합니다. 우리가 본 것처럼 바인딩 전파는 sync
대기열에 예약되어 결국 RunLoop에 의해 실행됩니다. 반면에 관찰자는 먼저 RunLoop 대기열에 예약 할 필요없이 감시 된 속성이 변경되면 즉시 실행됩니다. 관찰자와 바인딩이 모두 동일한 속성을 "감시"하면 관찰자는 바인딩이 업데이트되기 전에 항상 100 % 호출됩니다.
scheduleOnce
과 Ember.run.once
Ember의 자동 업데이트 템플릿의 큰 효율성 향상 중 하나는 RunLoop 덕분에 여러 개의 동일한 RunLoop 작업을 단일 작업으로 통합 ( "디 바운스") 할 수 있다는 사실에 기반합니다. run_loop.js
내부 를 살펴보면 이 동작을 촉진하는 기능이 관련 기능 scheduleOnce
과 Em.run.once
. 그들 사이의 차이점은 그들이 존재한다는 것을 아는 것만 큼 중요하지 않으며 실행 루프 동안 많은 부풀고 낭비적인 계산을 방지하기 위해 대기열에서 중복 작업을 버릴 수있는 방법입니다.
타이머는 어떻습니까?
'타이머'가 위에 나열된 기본 대기열 중 하나이지만 Ember는 RunLoop 테스트 케이스의 대기열 만 참조합니다. 이러한 대기열은 타이머가 마지막으로 실행되는 것에 대한 위 기사의 설명 중 일부를 기반으로 SproutCore 시대에 사용되었을 것으로 보입니다. Ember에서는 timers
대기열이 사용되지 않습니다. 대신 RunLoop은 내부적으로 관리되는 setTimeout
이벤트 ( invokeLaterTimers
함수 참조)에 의해 구동 될 수 있습니다.이 이벤트 는 기존의 모든 타이머를 반복하고 만료 된 모든 타이머를 실행하고 가장 빠른 미래 타이머를 결정하고 내부setTimeout
해당 이벤트에만 해당되며 실행시 RunLoop이 다시 회전합니다. 이 접근 방식은 각 타이머가 setTimeout을 호출하고 스스로 깨우는 것보다 더 효율적입니다.이 경우에는 setTimeout 호출을 한 번만 수행하면되고 RunLoop은 동시에 작동 할 수있는 모든 다른 타이머를 실행할 수있을만큼 똑똑합니다 시각.
sync
대기열을 사용한 추가 디 바운싱
다음은 런 루프의 모든 큐를 통과하는 루프 중간에있는 런 루프의 스 니펫입니다. sync
큐 의 특별한 경우에 유의하십시오 . sync
데이터가 모든 방향으로 전파되는 특히 휘발성 큐 Ember.beginPropertyChanges()
가 호출되어 관찰자가 실행되는 것을 방지하기 위해 호출되고 Ember.endPropertyChanges
. 이것은 현명합니다. sync
큐 를 플러시하는 과정 에서 객체의 속성이 최종 값에 도달하기 전에 여러 번 변경 될 가능성이 전적으로 가능하며 매 변경마다 관찰자를 즉시 실행하여 리소스를 낭비하고 싶지 않을 것입니다. .
if (queueName === 'sync')
{
log = Ember.LOG_BINDINGS;
if (log)
{
Ember.Logger.log('Begin: Flush Sync Queue');
}
Ember.beginPropertyChanges();
Ember.tryFinally(tryable, Ember.endPropertyChanges);
if (log)
{
Ember.Logger.log('End: Flush Sync Queue');
}
}
else
{
forEach.call(queue, iter);
}
도움이 되었기를 바랍니다. 저는이 글을 쓰기 위해서 확실히 꽤 많은 것을 배워야했습니다. 그것은 일종의 요점이었습니다.