11import { run_all } from './utils' ;
2- import { set_current_component } from './lifecycle' ;
2+ import { current_component , set_current_component } from './lifecycle' ;
33
44export const dirty_components = [ ] ;
55export const intros = { enabled : false } ;
@@ -31,23 +31,42 @@ export function add_flush_callback(fn) {
3131 flush_callbacks . push ( fn ) ;
3232}
3333
34- let flushing = false ;
34+ // flush() calls callbacks in this order:
35+ // 1. All beforeUpdate callbacks, in order: parents before children
36+ // 2. All bind:this callbacks, in reverse order: children before parents.
37+ // 3. All afterUpdate callbacks, in order: parents before children. EXCEPT
38+ // for afterUpdates called during the initial onMount, which are called in
39+ // reverse order: children before parents.
40+ // Since callbacks might update component values, which could trigger another
41+ // call to flush(), the following steps guard against this:
42+ // 1. During beforeUpdate, any updated components will be added to the
43+ // dirty_components array and will cause a reentrant call to flush(). Because
44+ // the flush index is kept outside the function, the reentrant call will pick
45+ // up where the earlier call left off and go through all dirty components. The
46+ // current_component value is saved and restored so that the reentrant call will
47+ // not interfere with the "parent" flush() call.
48+ // 2. bind:this callbacks cannot trigger new flush() calls.
49+ // 3. During afterUpdate, any updated components will NOT have their afterUpdate
50+ // callback called a second time; the seen_callbacks set, outside the flush()
51+ // function, guarantees this behavior.
3552const seen_callbacks = new Set ( ) ;
53+ let flushidx = 0 ; // Do *not* move this inside the flush() function
3654export function flush ( ) {
37- if ( flushing ) return ;
38- flushing = true ;
55+ const saved_component = current_component ;
3956
4057 do {
4158 // first, call beforeUpdate functions
4259 // and update components
43- for ( let i = 0 ; i < dirty_components . length ; i += 1 ) {
44- const component = dirty_components [ i ] ;
60+ while ( flushidx < dirty_components . length ) {
61+ const component = dirty_components [ flushidx ] ;
62+ flushidx ++ ;
4563 set_current_component ( component ) ;
4664 update ( component . $$ ) ;
4765 }
4866 set_current_component ( null ) ;
4967
5068 dirty_components . length = 0 ;
69+ flushidx = 0 ;
5170
5271 while ( binding_callbacks . length ) binding_callbacks . pop ( ) ( ) ;
5372
@@ -73,8 +92,8 @@ export function flush() {
7392 }
7493
7594 update_scheduled = false ;
76- flushing = false ;
7795 seen_callbacks . clear ( ) ;
96+ set_current_component ( saved_component ) ;
7897}
7998
8099function update ( $$ ) {
0 commit comments