this repo has no description
1import { run_all } from './utils.js';
2import { current_component, set_current_component } from './lifecycle.js';
3
4export const dirty_components = [];
5export const intros = { enabled: false };
6export const binding_callbacks = [];
7
8let render_callbacks = [];
9
10const flush_callbacks = [];
11
12const resolved_promise = /* @__PURE__ */ Promise.resolve();
13
14let update_scheduled = false;
15
16/** @returns {void} */
17export function schedule_update() {
18 if (!update_scheduled) {
19 update_scheduled = true;
20 resolved_promise.then(flush);
21 }
22}
23
24/** @returns {Promise<void>} */
25export function tick() {
26 schedule_update();
27 return resolved_promise;
28}
29
30/** @returns {void} */
31export function add_render_callback(fn) {
32 render_callbacks.push(fn);
33}
34
35/** @returns {void} */
36export function add_flush_callback(fn) {
37 flush_callbacks.push(fn);
38}
39
40// flush() calls callbacks in this order:
41// 1. All beforeUpdate callbacks, in order: parents before children
42// 2. All bind:this callbacks, in reverse order: children before parents.
43// 3. All afterUpdate callbacks, in order: parents before children. EXCEPT
44// for afterUpdates called during the initial onMount, which are called in
45// reverse order: children before parents.
46// Since callbacks might update component values, which could trigger another
47// call to flush(), the following steps guard against this:
48// 1. During beforeUpdate, any updated components will be added to the
49// dirty_components array and will cause a reentrant call to flush(). Because
50// the flush index is kept outside the function, the reentrant call will pick
51// up where the earlier call left off and go through all dirty components. The
52// current_component value is saved and restored so that the reentrant call will
53// not interfere with the "parent" flush() call.
54// 2. bind:this callbacks cannot trigger new flush() calls.
55// 3. During afterUpdate, any updated components will NOT have their afterUpdate
56// callback called a second time; the seen_callbacks set, outside the flush()
57// function, guarantees this behavior.
58const seen_callbacks = new Set();
59
60let flushidx = 0; // Do *not* move this inside the flush() function
61
62/** @returns {void} */
63export function flush() {
64 // Do not reenter flush while dirty components are updated, as this can
65 // result in an infinite loop. Instead, let the inner flush handle it.
66 // Reentrancy is ok afterwards for bindings etc.
67 if (flushidx !== 0) {
68 return;
69 }
70 const saved_component = current_component;
71 do {
72 // first, call beforeUpdate functions
73 // and update components
74 try {
75 while (flushidx < dirty_components.length) {
76 const component = dirty_components[flushidx];
77 flushidx++;
78 set_current_component(component);
79 update(component.$$);
80 }
81 } catch (e) {
82 // reset dirty state to not end up in a deadlocked state and then rethrow
83 dirty_components.length = 0;
84 flushidx = 0;
85 throw e;
86 }
87 set_current_component(null);
88 dirty_components.length = 0;
89 flushidx = 0;
90 while (binding_callbacks.length) binding_callbacks.pop()();
91 // then, once components are updated, call
92 // afterUpdate functions. This may cause
93 // subsequent updates...
94 for (let i = 0; i < render_callbacks.length; i += 1) {
95 const callback = render_callbacks[i];
96 if (!seen_callbacks.has(callback)) {
97 // ...so guard against infinite loops
98 seen_callbacks.add(callback);
99 callback();
100 }
101 }
102 render_callbacks.length = 0;
103 } while (dirty_components.length);
104 while (flush_callbacks.length) {
105 flush_callbacks.pop()();
106 }
107 update_scheduled = false;
108 seen_callbacks.clear();
109 set_current_component(saved_component);
110}
111
112/** @returns {void} */
113function update($$) {
114 if ($$.fragment !== null) {
115 $$.update();
116 run_all($$.before_update);
117 const dirty = $$.dirty;
118 $$.dirty = [-1];
119 $$.fragment && $$.fragment.p($$.ctx, dirty);
120 $$.after_update.forEach(add_render_callback);
121 }
122}
123
124/**
125 * Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`.
126 * @param {Function[]} fns
127 * @returns {void}
128 */
129export function flush_render_callbacks(fns) {
130 const filtered = [];
131 const targets = [];
132 render_callbacks.forEach((c) => (fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c)));
133 targets.forEach((c) => c());
134 render_callbacks = filtered;
135}