Skip to content

Commit ddb0bc3

Browse files
chore: optimise effects that only exist to return a teardown (#11936)
* create teardown effect * optimise * changeset * Update packages/svelte/src/internal/client/reactivity/types.d.ts Co-authored-by: MotionlessTrain <[email protected]> * use teardown in bind_property --------- Co-authored-by: MotionlessTrain <[email protected]>
1 parent 76388d0 commit ddb0bc3

File tree

12 files changed

+50
-45
lines changed

12 files changed

+50
-45
lines changed

.changeset/lemon-meals-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
chore: optimise effects that only exist to return a teardown

packages/svelte/src/internal/client/dom/elements/bindings/input.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DEV } from 'esm-env';
2-
import { render_effect, effect } from '../../../reactivity/effects.js';
2+
import { render_effect, effect, teardown } from '../../../reactivity/effects.js';
33
import { stringify } from '../../../render.js';
44
import { listen_to_event_and_reset_event } from './shared.js';
55
import * as e from '../../../errors.js';
@@ -103,14 +103,12 @@ export function bind_group(inputs, group_index, input, get_value, update) {
103103
}
104104
});
105105

106-
render_effect(() => {
107-
return () => {
108-
var index = binding_group.indexOf(input);
106+
teardown(() => {
107+
var index = binding_group.indexOf(input);
109108

110-
if (index !== -1) {
111-
binding_group.splice(index, 1);
112-
}
113-
};
109+
if (index !== -1) {
110+
binding_group.splice(index, 1);
111+
}
114112
});
115113

116114
effect(() => {
@@ -189,6 +187,7 @@ export function bind_files(input, get_value, update) {
189187
listen_to_event_and_reset_event(input, 'change', () => {
190188
update(input.files);
191189
});
190+
192191
render_effect(() => {
193192
input.files = get_value();
194193
});

packages/svelte/src/internal/client/dom/elements/bindings/media.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { hydrating } from '../../hydration.js';
2-
import { render_effect, effect } from '../../../reactivity/effects.js';
2+
import { render_effect, effect, teardown } from '../../../reactivity/effects.js';
33
import { listen } from './shared.js';
44

55
/** @param {TimeRanges} ranges */
@@ -52,7 +52,7 @@ export function bind_current_time(media, get_value, update) {
5252
updating = false;
5353
});
5454

55-
render_effect(() => () => cancelAnimationFrame(raf_id));
55+
teardown(() => cancelAnimationFrame(raf_id));
5656
}
5757

5858
/**

packages/svelte/src/internal/client/dom/elements/bindings/props.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render_effect } from '../../../reactivity/effects.js';
1+
import { teardown } from '../../../reactivity/effects.js';
22
import { get_descriptor } from '../../../utils.js';
33

44
/**
@@ -15,7 +15,7 @@ export function bind_prop(props, prop, value) {
1515

1616
if (desc && desc.set) {
1717
props[prop] = value;
18-
render_effect(() => () => {
18+
teardown(() => {
1919
props[prop] = null;
2020
});
2121
}

packages/svelte/src/internal/client/dom/elements/bindings/shared.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render_effect } from '../../../reactivity/effects.js';
1+
import { teardown } from '../../../reactivity/effects.js';
22
import { add_form_reset_listener } from '../misc.js';
33

44
/**
@@ -18,12 +18,10 @@ export function listen(target, events, handler, call_handler_immediately = true)
1818
target.addEventListener(name, handler);
1919
}
2020

21-
render_effect(() => {
22-
return () => {
23-
for (var name of events) {
24-
target.removeEventListener(name, handler);
25-
}
26-
};
21+
teardown(() => {
22+
for (var name of events) {
23+
target.removeEventListener(name, handler);
24+
}
2725
});
2826
}
2927

packages/svelte/src/internal/client/dom/elements/bindings/size.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { effect, render_effect } from '../../../reactivity/effects.js';
2-
import { untrack } from '../../../runtime.js';
1+
import { effect, teardown } from '../../../reactivity/effects.js';
32

43
/**
54
* Resize observer singleton.
@@ -89,7 +88,7 @@ export function bind_resize_observer(element, type, update) {
8988
: resize_observer_device_pixel_content_box;
9089

9190
var unsub = observer.observe(element, /** @param {any} entry */ (entry) => update(entry[type]));
92-
render_effect(() => unsub);
91+
teardown(unsub);
9392
}
9493

9594
/**

packages/svelte/src/internal/client/dom/elements/bindings/universal.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render_effect } from '../../../reactivity/effects.js';
1+
import { render_effect, teardown } from '../../../reactivity/effects.js';
22
import { listen } from './shared.js';
33

44
/**
@@ -57,10 +57,8 @@ export function bind_property(property, event_name, element, set, get) {
5757

5858
// @ts-ignore
5959
if (element === document.body || element === window || element === document) {
60-
render_effect(() => {
61-
return () => {
62-
element.removeEventListener(event_name, handler);
63-
};
60+
teardown(() => {
61+
element.removeEventListener(event_name, handler);
6462
});
6563
}
6664
}

packages/svelte/src/internal/client/dom/elements/bindings/window.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { effect, render_effect } from '../../../reactivity/effects.js';
1+
import { effect, render_effect, teardown } from '../../../reactivity/effects.js';
22
import { listen } from './shared.js';
33

44
/**
@@ -51,10 +51,8 @@ export function bind_window_scroll(type, get_value, update) {
5151
// Browsers don't fire the scroll event for the initial scroll position when scroll style isn't set to smooth
5252
effect(target_handler);
5353

54-
render_effect(() => {
55-
return () => {
56-
removeEventListener('scroll', target_handler);
57-
};
54+
teardown(() => {
55+
removeEventListener('scroll', target_handler);
5856
});
5957
}
6058

packages/svelte/src/internal/client/dom/elements/events.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render_effect } from '../../reactivity/effects.js';
1+
import { render_effect, teardown } from '../../reactivity/effects.js';
22
import { all_registered_events, root_event_handles } from '../../render.js';
33
import { define_property, is_array } from '../../utils.js';
44
import { hydrating } from '../hydration.js';
@@ -98,10 +98,8 @@ export function event(event_name, dom, handler, capture, passive) {
9898

9999
// @ts-ignore
100100
if (dom === document.body || dom === window || dom === document) {
101-
render_effect(() => {
102-
return () => {
103-
dom.removeEventListener(event_name, target_handler, options);
104-
};
101+
teardown(() => {
102+
dom.removeEventListener(event_name, target_handler, options);
105103
});
106104
}
107105
}

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import {
3030
ROOT_EFFECT,
3131
EFFECT_TRANSPARENT,
3232
DERIVED,
33-
UNOWNED
33+
UNOWNED,
34+
CLEAN
3435
} from '../constants.js';
3536
import { set } from './sources.js';
3637
import { remove } from '../dom/reconciler.js';
@@ -68,7 +69,7 @@ export function push_effect(effect, parent_effect) {
6869

6970
/**
7071
* @param {number} type
71-
* @param {(() => void | (() => void))} fn
72+
* @param {null | (() => void | (() => void))} fn
7273
* @param {boolean} sync
7374
* @returns {import('#client').Effect}
7475
*/
@@ -121,7 +122,7 @@ function create_effect(type, fn, sync) {
121122
} finally {
122123
set_is_flushing_effect(previously_flushing_effect);
123124
}
124-
} else {
125+
} else if (fn !== null) {
125126
schedule_effect(effect);
126127
}
127128

@@ -144,6 +145,16 @@ export function effect_active() {
144145
return false;
145146
}
146147

148+
/**
149+
* @param {() => void} fn
150+
*/
151+
export function teardown(fn) {
152+
const effect = create_effect(RENDER_EFFECT, null, false);
153+
set_signal_status(effect, CLEAN);
154+
effect.teardown = fn;
155+
return effect;
156+
}
157+
147158
/**
148159
* Internal representation of `$effect(...)`
149160
* @param {() => void | (() => void)} fn
@@ -364,7 +375,6 @@ export function destroy_effect(effect, remove_dom = true) {
364375
effect.dom =
365376
effect.deps =
366377
effect.parent =
367-
// @ts-expect-error
368378
effect.fn =
369379
null;
370380
}

packages/svelte/src/internal/client/reactivity/types.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface Value<V = unknown> extends Signal {
1818

1919
export interface Reaction extends Signal {
2020
/** The reaction function */
21-
fn: Function;
21+
fn: null | Function;
2222
/** Signals that this signal reads from */
2323
deps: null | Value[];
2424
/** First child effect created inside this signal */
@@ -40,7 +40,7 @@ export interface Effect extends Reaction {
4040
/** The associated component context */
4141
ctx: null | ComponentContext;
4242
/** The effect function */
43-
fn: () => void | (() => void);
43+
fn: null | (() => void | (() => void));
4444
/** The teardown function returned from the effect function */
4545
teardown: null | (() => void);
4646
/** Transition managers created with `$.transition` */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ function handle_error(error, effect, component_context) {
290290

291291
const component_stack = [];
292292

293-
const effect_name = effect.fn.name;
293+
const effect_name = effect.fn?.name;
294294

295295
if (effect_name) {
296296
component_stack.push(effect_name);
@@ -358,7 +358,7 @@ export function execute_reaction_fn(signal) {
358358
current_untracking = false;
359359

360360
try {
361-
let res = (0, signal.fn)();
361+
let res = /** @type {Function} */ (0, signal.fn)();
362362
let dependencies = /** @type {import('#client').Value<unknown>[]} **/ (signal.deps);
363363
if (current_dependencies !== null) {
364364
let i;

0 commit comments

Comments
 (0)