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 <timothy@familie-de-moor.nl>

* use teardown in bind_property

---------

Co-authored-by: MotionlessTrain <timothy@familie-de-moor.nl>
pull/11963/head
Rich Harris 7 months ago committed by GitHub
parent 76388d042c
commit ddb0bc3888
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: optimise effects that only exist to return a teardown

@ -1,5 +1,5 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { render_effect, effect } from '../../../reactivity/effects.js'; import { render_effect, effect, teardown } from '../../../reactivity/effects.js';
import { stringify } from '../../../render.js'; import { stringify } from '../../../render.js';
import { listen_to_event_and_reset_event } from './shared.js'; import { listen_to_event_and_reset_event } from './shared.js';
import * as e from '../../../errors.js'; import * as e from '../../../errors.js';
@ -103,14 +103,12 @@ export function bind_group(inputs, group_index, input, get_value, update) {
} }
}); });
render_effect(() => { teardown(() => {
return () => { var index = binding_group.indexOf(input);
var index = binding_group.indexOf(input);
if (index !== -1) { if (index !== -1) {
binding_group.splice(index, 1); binding_group.splice(index, 1);
} }
};
}); });
effect(() => { effect(() => {
@ -189,6 +187,7 @@ export function bind_files(input, get_value, update) {
listen_to_event_and_reset_event(input, 'change', () => { listen_to_event_and_reset_event(input, 'change', () => {
update(input.files); update(input.files);
}); });
render_effect(() => { render_effect(() => {
input.files = get_value(); input.files = get_value();
}); });

@ -1,5 +1,5 @@
import { hydrating } from '../../hydration.js'; import { hydrating } from '../../hydration.js';
import { render_effect, effect } from '../../../reactivity/effects.js'; import { render_effect, effect, teardown } from '../../../reactivity/effects.js';
import { listen } from './shared.js'; import { listen } from './shared.js';
/** @param {TimeRanges} ranges */ /** @param {TimeRanges} ranges */
@ -52,7 +52,7 @@ export function bind_current_time(media, get_value, update) {
updating = false; updating = false;
}); });
render_effect(() => () => cancelAnimationFrame(raf_id)); teardown(() => cancelAnimationFrame(raf_id));
} }
/** /**

@ -1,4 +1,4 @@
import { render_effect } from '../../../reactivity/effects.js'; import { teardown } from '../../../reactivity/effects.js';
import { get_descriptor } from '../../../utils.js'; import { get_descriptor } from '../../../utils.js';
/** /**
@ -15,7 +15,7 @@ export function bind_prop(props, prop, value) {
if (desc && desc.set) { if (desc && desc.set) {
props[prop] = value; props[prop] = value;
render_effect(() => () => { teardown(() => {
props[prop] = null; props[prop] = null;
}); });
} }

@ -1,4 +1,4 @@
import { render_effect } from '../../../reactivity/effects.js'; import { teardown } from '../../../reactivity/effects.js';
import { add_form_reset_listener } from '../misc.js'; import { add_form_reset_listener } from '../misc.js';
/** /**
@ -18,12 +18,10 @@ export function listen(target, events, handler, call_handler_immediately = true)
target.addEventListener(name, handler); target.addEventListener(name, handler);
} }
render_effect(() => { teardown(() => {
return () => { for (var name of events) {
for (var name of events) { target.removeEventListener(name, handler);
target.removeEventListener(name, handler); }
}
};
}); });
} }

@ -1,5 +1,4 @@
import { effect, render_effect } from '../../../reactivity/effects.js'; import { effect, teardown } from '../../../reactivity/effects.js';
import { untrack } from '../../../runtime.js';
/** /**
* Resize observer singleton. * Resize observer singleton.
@ -89,7 +88,7 @@ export function bind_resize_observer(element, type, update) {
: resize_observer_device_pixel_content_box; : resize_observer_device_pixel_content_box;
var unsub = observer.observe(element, /** @param {any} entry */ (entry) => update(entry[type])); var unsub = observer.observe(element, /** @param {any} entry */ (entry) => update(entry[type]));
render_effect(() => unsub); teardown(unsub);
} }
/** /**

@ -1,4 +1,4 @@
import { render_effect } from '../../../reactivity/effects.js'; import { render_effect, teardown } from '../../../reactivity/effects.js';
import { listen } from './shared.js'; import { listen } from './shared.js';
/** /**
@ -57,10 +57,8 @@ export function bind_property(property, event_name, element, set, get) {
// @ts-ignore // @ts-ignore
if (element === document.body || element === window || element === document) { if (element === document.body || element === window || element === document) {
render_effect(() => { teardown(() => {
return () => { element.removeEventListener(event_name, handler);
element.removeEventListener(event_name, handler);
};
}); });
} }
} }

@ -1,4 +1,4 @@
import { effect, render_effect } from '../../../reactivity/effects.js'; import { effect, render_effect, teardown } from '../../../reactivity/effects.js';
import { listen } from './shared.js'; import { listen } from './shared.js';
/** /**
@ -51,10 +51,8 @@ export function bind_window_scroll(type, get_value, update) {
// Browsers don't fire the scroll event for the initial scroll position when scroll style isn't set to smooth // Browsers don't fire the scroll event for the initial scroll position when scroll style isn't set to smooth
effect(target_handler); effect(target_handler);
render_effect(() => { teardown(() => {
return () => { removeEventListener('scroll', target_handler);
removeEventListener('scroll', target_handler);
};
}); });
} }

@ -1,4 +1,4 @@
import { render_effect } from '../../reactivity/effects.js'; import { render_effect, teardown } from '../../reactivity/effects.js';
import { all_registered_events, root_event_handles } from '../../render.js'; import { all_registered_events, root_event_handles } from '../../render.js';
import { define_property, is_array } from '../../utils.js'; import { define_property, is_array } from '../../utils.js';
import { hydrating } from '../hydration.js'; import { hydrating } from '../hydration.js';
@ -98,10 +98,8 @@ export function event(event_name, dom, handler, capture, passive) {
// @ts-ignore // @ts-ignore
if (dom === document.body || dom === window || dom === document) { if (dom === document.body || dom === window || dom === document) {
render_effect(() => { teardown(() => {
return () => { dom.removeEventListener(event_name, target_handler, options);
dom.removeEventListener(event_name, target_handler, options);
};
}); });
} }
} }

@ -30,7 +30,8 @@ import {
ROOT_EFFECT, ROOT_EFFECT,
EFFECT_TRANSPARENT, EFFECT_TRANSPARENT,
DERIVED, DERIVED,
UNOWNED UNOWNED,
CLEAN
} from '../constants.js'; } from '../constants.js';
import { set } from './sources.js'; import { set } from './sources.js';
import { remove } from '../dom/reconciler.js'; import { remove } from '../dom/reconciler.js';
@ -68,7 +69,7 @@ export function push_effect(effect, parent_effect) {
/** /**
* @param {number} type * @param {number} type
* @param {(() => void | (() => void))} fn * @param {null | (() => void | (() => void))} fn
* @param {boolean} sync * @param {boolean} sync
* @returns {import('#client').Effect} * @returns {import('#client').Effect}
*/ */
@ -121,7 +122,7 @@ function create_effect(type, fn, sync) {
} finally { } finally {
set_is_flushing_effect(previously_flushing_effect); set_is_flushing_effect(previously_flushing_effect);
} }
} else { } else if (fn !== null) {
schedule_effect(effect); schedule_effect(effect);
} }
@ -144,6 +145,16 @@ export function effect_active() {
return false; return false;
} }
/**
* @param {() => void} fn
*/
export function teardown(fn) {
const effect = create_effect(RENDER_EFFECT, null, false);
set_signal_status(effect, CLEAN);
effect.teardown = fn;
return effect;
}
/** /**
* Internal representation of `$effect(...)` * Internal representation of `$effect(...)`
* @param {() => void | (() => void)} fn * @param {() => void | (() => void)} fn
@ -364,7 +375,6 @@ export function destroy_effect(effect, remove_dom = true) {
effect.dom = effect.dom =
effect.deps = effect.deps =
effect.parent = effect.parent =
// @ts-expect-error
effect.fn = effect.fn =
null; null;
} }

@ -18,7 +18,7 @@ export interface Value<V = unknown> extends Signal {
export interface Reaction extends Signal { export interface Reaction extends Signal {
/** The reaction function */ /** The reaction function */
fn: Function; fn: null | Function;
/** Signals that this signal reads from */ /** Signals that this signal reads from */
deps: null | Value[]; deps: null | Value[];
/** First child effect created inside this signal */ /** First child effect created inside this signal */
@ -40,7 +40,7 @@ export interface Effect extends Reaction {
/** The associated component context */ /** The associated component context */
ctx: null | ComponentContext; ctx: null | ComponentContext;
/** The effect function */ /** The effect function */
fn: () => void | (() => void); fn: null | (() => void | (() => void));
/** The teardown function returned from the effect function */ /** The teardown function returned from the effect function */
teardown: null | (() => void); teardown: null | (() => void);
/** Transition managers created with `$.transition` */ /** Transition managers created with `$.transition` */

@ -290,7 +290,7 @@ function handle_error(error, effect, component_context) {
const component_stack = []; const component_stack = [];
const effect_name = effect.fn.name; const effect_name = effect.fn?.name;
if (effect_name) { if (effect_name) {
component_stack.push(effect_name); component_stack.push(effect_name);
@ -358,7 +358,7 @@ export function execute_reaction_fn(signal) {
current_untracking = false; current_untracking = false;
try { try {
let res = (0, signal.fn)(); let res = /** @type {Function} */ (0, signal.fn)();
let dependencies = /** @type {import('#client').Value<unknown>[]} **/ (signal.deps); let dependencies = /** @type {import('#client').Value<unknown>[]} **/ (signal.deps);
if (current_dependencies !== null) { if (current_dependencies !== null) {
let i; let i;

Loading…
Cancel
Save