Repository: sveltejs/svelte
File: packages/svelte/src/internal/client/reactivity/deriveds.js (JavaScript)

Code before:
			destroy_derived_effects(derived);
			value = update_reaction(derived);
		} finally {
			set_active_effect(prev_active_effect);
		}
	}

	return value;
}

/**
 * @param {Derived} derived
 * @returns {void}
 */
export function update_derived(derived) {
	var value = execute_derived(derived);

	if (!derived.equals(value)) {
		// if we have batch_values we don't actually set the value of the derived
		// otherwise blocks that depends on that derived will not be considered dirty
		// if the derived changes in a fork AND in a subsequent fork/normal state update
		// IF we are in a tracking context the derived value of the derived will be set
		// in the batch_values map thus updating it for this batch otherwise it will just be updated
		// again during the `get` call we also prevent setting the value if we are in a fork
		// this will lead to over executing of the derived but would lead to correct values
		if (batch_values === null && current_batch?.is_fork !== true) {
			derived.v = value;
		}
		derived.wv = increment_write_version();
	}

	// don't mark derived clean if we're reading it inside a
	// cleanup function, or it will cache a stale value
	if (is_destroying_effect) {
		return;
	}

	// During time traveling we don't want to reset the status so that
	// traversal of the graph in the other batches still happens
	if (batch_values !== null) {
		// only cache the value if we're in a tracking context, otherwise we won't
		// clear the cache in `mark_reactions` when dependencies are updated
		if (effect_tracking()) {
			batch_values.set(derived, value);
		}
	} else {
		var status = (derived.f & CONNECTED) === 0 ? MAYBE_DIRTY : CLEAN;
		set_signal_status(derived, status);
	}
}


Review comment (bug):
Revisiting this: We only want to do this when a fork is running, right? If so, then we can be sure that we don't have to worry about the edge cases about `effect_tracking()` etc, because either we are inside the `fork` function itself, which is only run once and so perf recalculation concerns are not a problem, or we reenter the fork after async work at which point `effect_tracking()` will be true in all cases that matter (recalculation via `untracked` inside `$derived` should be super rare).

```suggestion
		if (!current_batch?.is_fork) {
```

Code after:
			destroy_derived_effects(derived);
			value = update_reaction(derived);
		} finally {
			set_active_effect(prev_active_effect);
		}
	}

	return value;
}

/**
 * @param {Derived} derived
 * @returns {void}
 */
export function update_derived(derived) {
	var value = execute_derived(derived);

	if (!derived.equals(value)) {
		// in a fork, we don't update the underlying value, just `batch_values`.
		// the underlying value will be updated when the fork is committed.
		// otherwise, the next time we get here after a 'real world' state
		// change, `derived.equals` may incorrectly return `true`
		if (!current_batch?.is_fork) {
			derived.v = value;
		}

		derived.wv = increment_write_version();
	}

	// don't mark derived clean if we're reading it inside a
	// cleanup function, or it will cache a stale value
	if (is_destroying_effect) {
		return;
	}

	// During time traveling we don't want to reset the status so that
	// traversal of the graph in the other batches still happens
	if (batch_values !== null) {
		// only cache the value if we're in a tracking context, otherwise we won't
		// clear the cache in `mark_reactions` when dependencies are updated
		if (effect_tracking()) {
			batch_values.set(derived, value);
		}
	} else {
		var status = (derived.f & CONNECTED) === 0 ? MAYBE_DIRTY : CLEAN;
		set_signal_status(derived, status);
	}
}