Skip to content

Commit 2781559

Browse files
authored
chore: refactor reactivity code (#10760)
* split destroy_signal into destroy_effect and destroy_derived * remove unused code * remove derived.y * remove unused code * lint * use alias * simplify * remove unused code * remove unused code * rename value.c to value.reactions, remove from effect type * rename consumer to reaction, for greater consistency * remove push_destroy_fn, we don't need it * more clarity * this is just incorrect * align with 10594 * rename signal.i to signal.fn * rename signal.d to signal.deps * remove some unnecessary ceremony * remove unnecessary code * believe it or not this is faster. it also looks cooler * tidy up * remove derived.x * tighten up mark_subtree_insert * remove derived.b * tidy up * tidy up * effect.x -> effect.ctx * signal.b -> signal.block * tighten up * tidy up * separate reaction.r into reaction.effects and reaction.deriveds * make Derived and Effect inherit from Reaction, rather than Reaction being a union of Derived and Effect * remove unused stuff * tidy up * rename effect.v to effect.teardown * rename effect.y to effect.ondestroy * tidy up * inline doc * rename * simplify * tidy up * tweak * remove unnecessary if check * fix effect teardown bug * test * stfu eslint * remove unused is_runes call * remove unused argument * this code doesnt do anything * typos * unused import * source needs no flags * tidy up * tidy up * move some code * tidy up * set current signal status, not dependency status * simplify * remove unused code * tidy up * rename — is_signal_dirty sounds like a pure function but it isnt * rename value.w to value.version * rename * simplify * MaybeSignal -> MaybeSource * unused argument * use default parameters --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 3196077 commit 2781559

File tree

18 files changed

+514
-565
lines changed

18 files changed

+514
-565
lines changed

packages/svelte/src/internal/client/constants.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export const SOURCE = 1;
21
export const DERIVED = 1 << 1;
32
export const EFFECT = 1 << 2;
43
export const PRE_EFFECT = 1 << 3;

packages/svelte/src/internal/client/custom-element.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createClassComponent } from '../../legacy/legacy-client.js';
2-
import { destroy_signal } from './runtime.js';
3-
import { render_effect } from './reactivity/effects.js';
2+
import { destroy_effect, render_effect } from './reactivity/effects.js';
43
import { open, close } from './render.js';
54
import { define_property } from './utils.js';
65

@@ -199,7 +198,7 @@ if (typeof HTMLElement === 'function') {
199198
Promise.resolve().then(() => {
200199
if (!this.$$cn) {
201200
this.$$c.$destroy();
202-
destroy_signal(this.$$me);
201+
destroy_effect(this.$$me);
203202
this.$$c = undefined;
204203
}
205204
});

packages/svelte/src/internal/client/dom/blocks/await.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
import { is_promise } from '../../../common.js';
22
import { hydrate_block_anchor } from '../../hydration.js';
33
import { remove } from '../../reconciler.js';
4-
import {
5-
current_block,
6-
destroy_signal,
7-
execute_effect,
8-
flushSync,
9-
push_destroy_fn
10-
} from '../../runtime.js';
11-
import { render_effect } from '../../reactivity/effects.js';
4+
import { current_block, execute_effect, flushSync } from '../../runtime.js';
5+
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
126
import { trigger_transitions } from '../../transitions.js';
137
import { AWAIT_BLOCK, UNINITIALIZED } from '../../constants.js';
148

@@ -74,7 +68,7 @@ export function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
7468
remove(render.d);
7569
render.d = null;
7670
}
77-
destroy_signal(render.e);
71+
destroy_effect(render.e);
7872
render.e = null;
7973
}
8074
}
@@ -181,7 +175,7 @@ export function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
181175
block,
182176
false
183177
);
184-
push_destroy_fn(await_effect, () => {
178+
await_effect.ondestroy = () => {
185179
let render = current_render;
186180
latest_token = {};
187181
while (render !== null) {
@@ -191,10 +185,10 @@ export function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
191185
}
192186
const effect = render.e;
193187
if (effect !== null) {
194-
destroy_signal(effect);
188+
destroy_effect(effect);
195189
}
196190
render = render.p;
197191
}
198-
});
192+
};
199193
block.e = await_effect;
200194
}

packages/svelte/src/internal/client/dom/blocks/each.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {
1616
} from '../../hydration.js';
1717
import { clear_text_content, empty, map_get, map_set } from '../../operations.js';
1818
import { insert, remove } from '../../reconciler.js';
19-
import { current_block, destroy_signal, execute_effect, push_destroy_fn } from '../../runtime.js';
20-
import { render_effect } from '../../reactivity/effects.js';
19+
import { current_block, execute_effect } from '../../runtime.js';
20+
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
2121
import { source, mutable_source, set } from '../../reactivity/sources.js';
2222
import { trigger_transitions } from '../../transitions.js';
2323
import { is_array, is_frozen } from '../../utils.js';
@@ -91,7 +91,7 @@ export function create_each_item_block(item, index, key) {
9191
* @param {() => V[]} collection
9292
* @param {number} flags
9393
* @param {null | ((item: V) => string)} key_fn
94-
* @param {(anchor: null, item: V, index: import('../../types.js').MaybeSignal<number>) => void} render_fn
94+
* @param {(anchor: null, item: V, index: import('#client').MaybeSource<number>) => void} render_fn
9595
* @param {null | ((anchor: Node) => void)} fallback_fn
9696
* @param {typeof reconcile_indexed_array | reconcile_tracked_array} reconcile_fn
9797
* @returns {void}
@@ -133,7 +133,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
133133
remove(fallback.d);
134134
fallback.d = null;
135135
}
136-
destroy_signal(fallback.e);
136+
destroy_effect(fallback.e);
137137
fallback.e = null;
138138
}
139139
}
@@ -261,7 +261,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
261261
set_current_hydration_fragment([]);
262262
}
263263

264-
push_destroy_fn(each, () => {
264+
each.ondestroy = () => {
265265
const flags = block.f;
266266
const anchor_node = block.a;
267267
const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
@@ -273,14 +273,14 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
273273
}
274274
const effect = fallback.e;
275275
if (effect !== null) {
276-
destroy_signal(effect);
276+
destroy_effect(effect);
277277
}
278278
fallback = fallback.p;
279279
}
280280
// Clear the array
281281
reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys);
282-
destroy_signal(/** @type {import('../../types.js').Effect} */ (render));
283-
});
282+
destroy_effect(/** @type {import('#client').Effect} */ (render));
283+
};
284284

285285
block.e = each;
286286
}
@@ -291,7 +291,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
291291
* @param {() => V[]} collection
292292
* @param {number} flags
293293
* @param {null | ((item: V) => string)} key_fn
294-
* @param {(anchor: null, item: V, index: import('../../types.js').MaybeSignal<number>) => void} render_fn
294+
* @param {(anchor: null, item: V, index: import('#client').MaybeSource<number>) => void} render_fn
295295
* @param {null | ((anchor: Node) => void)} fallback_fn
296296
* @returns {void}
297297
*/
@@ -304,7 +304,7 @@ export function each_keyed(anchor_node, collection, flags, key_fn, render_fn, fa
304304
* @param {Element | Comment} anchor_node
305305
* @param {() => V[]} collection
306306
* @param {number} flags
307-
* @param {(anchor: null, item: V, index: import('../../types.js').MaybeSignal<number>) => void} render_fn
307+
* @param {(anchor: null, item: V, index: import('#client').MaybeSource<number>) => void} render_fn
308308
* @param {null | ((anchor: Node) => void)} fallback_fn
309309
* @returns {void}
310310
*/
@@ -904,7 +904,7 @@ export function destroy_each_item_block(
904904
if (!controlled && dom !== null) {
905905
remove(dom);
906906
}
907-
destroy_signal(/** @type {import('../../types.js').Effect} */ (block.e));
907+
destroy_effect(/** @type {import('#client').Effect} */ (block.e));
908908
}
909909

910910
/**

packages/svelte/src/internal/client/dom/blocks/if.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {
66
set_current_hydration_fragment
77
} from '../../hydration.js';
88
import { remove } from '../../reconciler.js';
9-
import { current_block, destroy_signal, execute_effect, push_destroy_fn } from '../../runtime.js';
10-
import { render_effect } from '../../reactivity/effects.js';
9+
import { current_block, execute_effect } from '../../runtime.js';
10+
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
1111
import { trigger_transitions } from '../../transitions.js';
1212

1313
/** @returns {import('../../types.js').IfBlock} */
@@ -167,15 +167,15 @@ export function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn)
167167
true
168168
);
169169
block.ae = alternate_effect;
170-
push_destroy_fn(if_effect, () => {
170+
if_effect.ondestroy = () => {
171171
if (consequent_dom !== null) {
172172
remove(consequent_dom);
173173
}
174174
if (alternate_dom !== null) {
175175
remove(alternate_dom);
176176
}
177-
destroy_signal(consequent_effect);
178-
destroy_signal(alternate_effect);
179-
});
177+
destroy_effect(consequent_effect);
178+
destroy_effect(alternate_effect);
179+
};
180180
block.e = if_effect;
181181
}

packages/svelte/src/internal/client/dom/blocks/key.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { UNINITIALIZED, KEY_BLOCK } from '../../constants.js';
22
import { hydrate_block_anchor } from '../../hydration.js';
33
import { remove } from '../../reconciler.js';
4-
import { current_block, destroy_signal, execute_effect, push_destroy_fn } from '../../runtime.js';
5-
import { render_effect } from '../../reactivity/effects.js';
4+
import { current_block, execute_effect } from '../../runtime.js';
5+
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
66
import { trigger_transitions } from '../../transitions.js';
77
import { safe_not_equal } from '../../reactivity/equality.js';
88

@@ -58,7 +58,7 @@ export function key_block(anchor_node, key, render_fn) {
5858
remove(render.d);
5959
render.d = null;
6060
}
61-
destroy_signal(render.e);
61+
destroy_effect(render.e);
6262
render.e = null;
6363
}
6464
}
@@ -122,7 +122,7 @@ export function key_block(anchor_node, key, render_fn) {
122122
// we trigger the effect after.
123123
render();
124124
mounted = true;
125-
push_destroy_fn(key_effect, () => {
125+
key_effect.ondestroy = () => {
126126
let render = current_render;
127127
while (render !== null) {
128128
const dom = render.d;
@@ -131,10 +131,10 @@ export function key_block(anchor_node, key, render_fn) {
131131
}
132132
const effect = render.e;
133133
if (effect !== null) {
134-
destroy_signal(effect);
134+
destroy_effect(effect);
135135
}
136136
render = render.p;
137137
}
138-
});
138+
};
139139
block.e = key_effect;
140140
}

packages/svelte/src/internal/client/proxy.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
import { DEV } from 'esm-env';
2-
import {
3-
get,
4-
updating_derived,
5-
batch_inspect,
6-
current_component_context,
7-
untrack
8-
} from './runtime.js';
2+
import { get, batch_inspect, current_component_context, untrack } from './runtime.js';
93
import { effect_active } from './reactivity/effects.js';
104
import {
115
array_prototype,
@@ -20,6 +14,7 @@ import {
2014
import { add_owner, check_ownership, strip_owner } from './dev/ownership.js';
2115
import { mutable_source, source, set } from './reactivity/sources.js';
2216
import { STATE_SYMBOL, UNINITIALIZED } from './constants.js';
17+
import { updating_derived } from './reactivity/deriveds.js';
2318

2419
/**
2520
* @template T
Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,52 @@
11
import { DEV } from 'esm-env';
2-
import { CLEAN, DERIVED, UNINITIALIZED, UNOWNED } from '../constants.js';
3-
import { current_block, current_consumer, current_effect } from '../runtime.js';
4-
import { push_reference } from './effects.js';
5-
import { default_equals, safe_equal } from './equality.js';
2+
import { CLEAN, DERIVED, DESTROYED, DIRTY, MAYBE_DIRTY, UNOWNED } from '../constants.js';
3+
import {
4+
current_reaction,
5+
current_effect,
6+
destroy_children,
7+
remove_reactions,
8+
set_signal_status,
9+
mark_reactions,
10+
current_skip_reaction,
11+
execute_reaction_fn
12+
} from '../runtime.js';
13+
import { equals, safe_equals } from './equality.js';
14+
15+
export let updating_derived = false;
616

717
/**
818
* @template V
919
* @param {() => V} fn
10-
* @returns {import('../types.js').Derived<V>}
20+
* @returns {import('#client').Derived<V>}
1121
*/
1222
/*#__NO_SIDE_EFFECTS__*/
1323
export function derived(fn) {
14-
let flags = DERIVED | CLEAN;
24+
let flags = DERIVED | DIRTY;
1525
if (current_effect === null) flags |= UNOWNED;
1626

1727
/** @type {import('#client').Derived<V>} */
1828
const signal = {
19-
b: current_block,
20-
c: null,
21-
d: null,
22-
e: default_equals,
29+
reactions: null,
30+
deps: null,
31+
equals,
2332
f: flags,
24-
i: fn,
25-
r: null,
26-
// @ts-expect-error
27-
v: UNINITIALIZED,
28-
w: 0,
29-
x: null,
30-
y: null
33+
fn,
34+
effects: null,
35+
deriveds: null,
36+
v: /** @type {V} */ (null),
37+
version: 0
3138
};
3239

3340
if (DEV) {
3441
/** @type {import('#client').DerivedDebug} */ (signal).inspect = new Set();
3542
}
3643

37-
if (current_consumer !== null) {
38-
push_reference(current_consumer, signal);
44+
if (current_reaction !== null) {
45+
if (current_reaction.deriveds === null) {
46+
current_reaction.deriveds = [signal];
47+
} else {
48+
current_reaction.deriveds.push(signal);
49+
}
3950
}
4051

4152
return signal;
@@ -49,6 +60,52 @@ export function derived(fn) {
4960
/*#__NO_SIDE_EFFECTS__*/
5061
export function derived_safe_equal(fn) {
5162
const signal = derived(fn);
52-
signal.e = safe_equal;
63+
signal.equals = safe_equals;
5364
return signal;
5465
}
66+
67+
/**
68+
* @param {import('#client').Derived} derived
69+
* @param {boolean} force_schedule
70+
* @returns {void}
71+
*/
72+
export function update_derived(derived, force_schedule) {
73+
var previous_updating_derived = updating_derived;
74+
updating_derived = true;
75+
destroy_children(derived);
76+
var value = execute_reaction_fn(derived);
77+
updating_derived = previous_updating_derived;
78+
79+
var status =
80+
(current_skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null
81+
? MAYBE_DIRTY
82+
: CLEAN;
83+
84+
set_signal_status(derived, status);
85+
86+
if (!derived.equals(value)) {
87+
derived.v = value;
88+
mark_reactions(derived, DIRTY, force_schedule);
89+
90+
if (DEV && force_schedule) {
91+
for (var fn of /** @type {import('#client').DerivedDebug} */ (derived).inspect) fn();
92+
}
93+
}
94+
}
95+
96+
/**
97+
* @param {import('#client').Derived} signal
98+
* @returns {void}
99+
*/
100+
export function destroy_derived(signal) {
101+
destroy_children(signal);
102+
remove_reactions(signal, 0);
103+
set_signal_status(signal, DESTROYED);
104+
105+
signal.effects =
106+
signal.deps =
107+
signal.reactions =
108+
// @ts-expect-error `signal.fn` cannot be `null` while the signal is alive
109+
signal.fn =
110+
null;
111+
}

0 commit comments

Comments
 (0)