program tip

Ember RunLoop이란 무엇이며 어떻게 작동합니까?

radiobox 2020. 8. 25. 07:52
반응형

Ember RunLoop이란 무엇이며 어떻게 작동합니까?


Ember RunLoop의 작동 원리와 작동 원리를 이해하려고합니다. 문서를 살펴 보았지만 여전히 많은 질문이 있습니다. 나중에 일부 코드의 실행을 연기해야 ​​할 때 이름 공간 내에서 적절한 방법을 선택할 수 있도록 RunLoop의 작동 방식을 더 잘 이해하고 싶습니다.

  • Ember RunLoop은 언제 시작됩니다. 라우터, 뷰 또는 컨트롤러 또는 다른 것에 의존합니까?
  • 대략 얼마나 걸리는지 (나는 이것이 많은 것을 요구하고 의존하는 것이 다소 어리 석다는 것을 알고 있지만 일반적인 아이디어를 찾고 있거나 아마도 실행 루프가 걸릴 수있는 최소 또는 최대 시간이있는 경우)
  • RunLoop이 항상 실행되고 있는지 아니면 실행 시작부터 끝까지의 기간을 나타내는 것일뿐 일정 시간 동안 실행되지 않을 수 있습니다.
  • 하나의 RunLoop 내에서 뷰가 생성되는 경우 루프가 종료 될 때 모든 콘텐츠가 DOM으로 들어가는 것이 보장됩니까?

이것이 매우 기본적인 질문이라면 저를 용서하십시오, 이것들을 이해하면 저와 같은 멍청이가 Ember를 더 잘 사용하는 데 도움이 될 것이라고 생각합니다.


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사이를 앞뒤로 반복하는 대신 invokeLastEmber가 '대기열'목록을 제공한다는 것입니다. 실행 루프가 진행되는 동안 작업이 속한 대기열을 지정하여 작업 (실행 루프 중에 호출되는 함수)을 예약 할 수 있습니다 (출처 :) 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이 이전에 플러시 된 모든 대기열을 살펴보고 새 작업이 예약되었는지 확인하는 것입니다. 그럴 경우, 수행되지 않은 예약 된 작업으로 가장 빠른 대기열의 시작 부분에서 시작하고 대기열을 비워야하며 모든 대기열이 완전히 비워 질 때까지 단계를 계속 추적하고 필요할 때 다시 시작해야합니다.

That's the essence of the algorithm. That's how bound data gets propagated through the app. You can expect that once a RunLoop runs to completion, all of the bound data will be fully propagated. So, what about DOM elements?

The order of the queues, including the ones added in by the Ember Views library, is important here. Notice that render and afterRender come after sync, and action. The sync queue contains all the actions for propagating bound data. (action, after that, is only sparsely used in the Ember source). Based on the above algorithm, it is guaranteed that by the time the RunLoop gets to the render queue, all of the data-bindings will have finished synchronizing. This is by design: you wouldn't want to perform the expensive task of rendering DOM elements before sync'ing the data-bindings, since that would likely require re-rendering DOM elements with updated data -- obviously a very inefficient and error-prone way of emptying all of the RunLoop queues. So Ember intelligently blasts through all the data-binding work it can before rendering the DOM elements in the render queue.

So, finally, to answer your question, yes, you can expect that any necessary DOM renderings will have taken place by the time Ember.run finishes. Here's a jsFiddle to demonstrate: http://jsfiddle.net/machty/6p6XJ/328/

Other things to know about the RunLoop

Observers vs. Bindings

It's important to note that Observers and Bindings, while having the similar functionality of responding to changes in a "watched" property, behave totally differently in the context of a RunLoop. Binding propagation, as we've seen, gets scheduled into the sync queue to eventually be executed by the RunLoop. Observers, on the other hand, fire immediately when the watched property changes without having to be first scheduled into a RunLoop queue. If an Observer and a binding all "watch" the same property, the observer will always be called 100% of the time earlier than the binding will be updated.

scheduleOnce and Ember.run.once

One of the big efficiency boosts in Ember's auto-updating templates is based on the fact that, thanks to the RunLoop, multiple identical RunLoop actions can be coalesced ("debounced", if you will) into a single action. If you look into the run_loop.js internals, you'll see the functions that facilitate this behavior are the related functions scheduleOnce and Em.run.once. The difference between them isn't so important as knowing they exist, and how they can discard duplicate actions in queue to prevent a lot of bloated, wasteful calculation during the run loop.

What about timers?

Even though 'timers' is one of the default queues listed above, Ember only makes reference to the queue in their RunLoop test cases. It seems that such a queue would have been used in the SproutCore days based on some of the descriptions from the above articles about timers being the last thing to fire. In Ember, the timers queue isn't used. Instead, the RunLoop can be spun up by an internally managed setTimeout event (see the invokeLaterTimers function), which is intelligent enough to loop through all the existing timers, fire all the ones that have expired, determine the earliest future timer, and set an internal setTimeout for that event only, which will spin up the RunLoop again when it fires. This approach is more efficient than having each timer call setTimeout and wake itself up, since in this case, only one setTimeout call needs to be made, and the RunLoop is smart enough to fire all the different timers that might be going off at the same time.

Further debouncing with the sync queue

Here's a snippet from the run loop, in the middle of a loop through all the queues in the run loop. Note the special case for the sync queue: because sync is a particularly volatile queue, in which data is being propagated in every direction, Ember.beginPropertyChanges() is called to prevent any observers from being fired, followed by a call to Ember.endPropertyChanges. This is wise: if in the course of flushing the sync queue, it's entirely possible that a property on an object will change multiple times before resting on its final value, and you wouldn't want to waste resources by immediately firing observers per every single change.

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);
}

Hope this helps. I definitely had to learn quite a bit just to write this thing, which was kind of the point.

참고URL : https://stackoverflow.com/questions/13597869/what-is-ember-runloop-and-how-does-it-work

반응형