diff --git a/.changeset/blue-waves-sneeze.md b/.changeset/blue-waves-sneeze.md new file mode 100644 index 0000000000..12f8d663c7 --- /dev/null +++ b/.changeset/blue-waves-sneeze.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +chore: optimise effects diff --git a/packages/svelte/src/internal/client/dom/legacy/lifecycle.js b/packages/svelte/src/internal/client/dom/legacy/lifecycle.js index ae4c66ccbb..019dad9490 100644 --- a/packages/svelte/src/internal/client/dom/legacy/lifecycle.js +++ b/packages/svelte/src/internal/client/dom/legacy/lifecycle.js @@ -1,14 +1,6 @@ -import { CLEAN } from '../../constants.js'; import { run, run_all } from '../../../shared/utils.js'; import { user_pre_effect, user_effect } from '../../reactivity/effects.js'; -import { - current_component_context, - current_effect, - deep_read_state, - flush_local_render_effects, - get, - untrack -} from '../../runtime.js'; +import { current_component_context, deep_read_state, get, untrack } from '../../runtime.js'; /** * Legacy-mode only: Call `onMount` callbacks and set up `beforeUpdate`/`afterUpdate` effects @@ -26,13 +18,6 @@ export function init() { user_pre_effect(() => { observe_all(context); run_all(callbacks.b); - // beforeUpdate might change state that affects rendering, ensure the render effects following from it - // are batched up with the current run. Avoids for example child components rerunning when they're - // now hidden because beforeUpdate did set an if block to false. - const parent = current_effect?.parent; - if (parent != null && (parent.f & CLEAN) === 0) { - flush_local_render_effects(parent); - } }); } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index ddbeaafe36..a378411041 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -521,9 +521,27 @@ function infinite_loop_guard() { */ function flush_queued_root_effects(root_effects) { infinite_loop_guard(); - for (var i = 0; i < root_effects.length; i++) { - var signal = root_effects[i]; - flush_nested_effects(signal, RENDER_EFFECT | EFFECT); + + var previously_flushing_effect = is_flushing_effect; + is_flushing_effect = true; + + try { + for (var i = 0; i < root_effects.length; i++) { + var effect = root_effects[i]; + + // When working with custom elements, the root effects might not have a root + if (effect.first === null && (effect.f & BRANCH_EFFECT) === 0) { + flush_queued_effects([effect]); + } else { + /** @type {import('#client').Effect[]} */ + var collected_effects = []; + + process_effects(effect, collected_effects); + flush_queued_effects(collected_effects); + } + } + } finally { + is_flushing_effect = previously_flushing_effect; } } @@ -592,12 +610,10 @@ export function schedule_effect(signal) { * effects to be flushed. * * @param {import('#client').Effect} effect - * @param {number} filter_flags - * @param {boolean} shallow * @param {import('#client').Effect[]} collected_effects * @returns {void} */ -function process_effects(effect, filter_flags, shallow, collected_effects) { +function process_effects(effect, collected_effects) { var current_effect = effect.first; var effects = []; @@ -621,13 +637,14 @@ function process_effects(effect, filter_flags, shallow, collected_effects) { // Child might have been mutated since running the effect child = current_effect.first; } - if (!shallow && child !== null) { + + if (child !== null) { current_effect = child; continue; } } else if ((flags & EFFECT) !== 0) { if (is_branch || is_clean) { - if (!shallow && child !== null) { + if (child !== null) { current_effect = child; continue; } @@ -657,62 +674,15 @@ function process_effects(effect, filter_flags, shallow, collected_effects) { current_effect = sibling; } - if (effects.length > 0) { - // We might be dealing with many effects here, far more than can be spread into - // an array push call (callstack overflow). So let's deal with each effect in a loop. - for (var i = 0; i < effects.length; i++) { - if ((filter_flags & EFFECT) !== 0) { - collected_effects.push(effects[i]); - } - if (!shallow) { - process_effects(effects[i], filter_flags, false, collected_effects); - } - } + // We might be dealing with many effects here, far more than can be spread into + // an array push call (callstack overflow). So let's deal with each effect in a loop. + for (var i = 0; i < effects.length; i++) { + child = effects[i]; + collected_effects.push(child); + process_effects(child, collected_effects); } } -/** - * - * This function recursively collects effects in topological order from the starting effect passed in. - * Effects will be collected when they match the filtered bitwise flag passed in only. The collected - * array will be populated with all the effects. - * - * @param {import('#client').Effect} effect - * @param {number} filter_flags - * @param {boolean} [shallow] - * @returns {void} - */ -function flush_nested_effects(effect, filter_flags, shallow = false) { - /** @type {import('#client').Effect[]} */ - var collected_effects = []; - - var previously_flushing_effect = is_flushing_effect; - is_flushing_effect = true; - - try { - // When working with custom elements, the root effects might not have a root - if (effect.first === null && (effect.f & BRANCH_EFFECT) === 0) { - flush_queued_effects([effect]); - } else { - process_effects(effect, filter_flags, shallow, collected_effects); - flush_queued_effects(collected_effects); - } - } finally { - is_flushing_effect = previously_flushing_effect; - } -} - -/** - * @param {import('#client').Effect} effect - * @returns {void} - */ -export function flush_local_render_effects(effect) { - infinite_loop_guard(); - // We are entering a new flush sequence, so ensure counter is reset. - flush_count = 0; - flush_nested_effects(effect, RENDER_EFFECT, true); -} - /** * Internal version of `flushSync` with the option to not flush previous effects. * Returns the result of the passed function, if given.