remove some dead weight

async-another-try
Simon Holthausen 4 days ago
parent ab75873a57
commit 387995cd63
No known key found for this signature in database

@ -240,12 +240,6 @@ export class Batch {
*/
#dirty_deriveds = new Set();
/**
* Deferred derived effects that are MAYBE_DIRTY
* @type {Set<Derived>}
*/
#maybe_dirty_deriveds = new Set();
/**
* A map of branches that still exist, but will be destroyed when this batch
* is committed — we skip over these during `process`.
@ -438,22 +432,9 @@ export class Batch {
}
for (const d of this.#dirty_deriveds) {
this.#maybe_dirty_deriveds.delete(d);
set_signal_status(d, DIRTY);
}
for (const d of this.#maybe_dirty_deriveds) {
set_signal_status(d, MAYBE_DIRTY);
}
// An earlier batch might have created new branches which contain effects that we need
// to mark as dirty to also execute them.
// TODO does this make the similar logic in fork.commit below obsolete?
// TODO feels correct but breaks many tests
// for (const [s, [_, is_derived]] of this.current) {
// if (!is_derived) this.mark(s, MAYBE_DIRTY, true);
// }
this.apply();
/** @type {Effect[]} */
@ -806,55 +787,7 @@ export class Batch {
batch.async_deriveds.clear();
// Mark is not guaranteed not touch these, so we transfer them
this.transfer_effects(
batch.#dirty_effects,
batch.#maybe_dirty_effects,
batch.#dirty_deriveds,
batch.#maybe_dirty_deriveds
);
/**
* mark all effects that depend on `batch.current`, except the
* async effects that we just resolved (TODO unless they depend
* on values in this batch that are NOT in the later batch?).
* Through this we also will populate the correct #skipped_branches,
* oncommit callbacks etc, so we don't need to merge them separately.
* @param {Value} value
*/
const mark = (value) => {
var reactions = value.reactions;
if (reactions === null) return;
// skip if value is derived and is neither dirty nor maybe dirty. transitive
// deriveds (a derived depending on another derived) are only MAYBE_DIRTY, so
// we must continue traversing them to reach the effects that depend on them
if ((value.f & DERIVED) !== 0 && (value.f & (DIRTY | MAYBE_DIRTY)) === 0) {
return;
}
for (const reaction of reactions) {
var flags = reaction.f;
if ((flags & DERIVED) !== 0) {
mark(/** @type {Derived} */ (reaction));
} else {
var effect = /** @type {Effect} */ (reaction);
// TODO this overfires e.g. for async-state-new-branch-fork-5 where it reruns
// the Child async effects with "world" after commit+first resolve; generally
// overfires everywhere where the merged effect has async deriveds that are not
// in the earlier batch, which it definitely should not rerun.
if (flags & (ASYNC | BLOCK_EFFECT) && !this.async_deriveds.has(effect)) {
this.#maybe_dirty_effects.delete(effect);
set_signal_status(effect, DIRTY);
this.schedule(effect);
}
}
}
};
// for (const source of this.current.keys()) {
// mark(source);
// }
this.transfer_effects(batch.#dirty_effects, batch.#maybe_dirty_effects, batch.#dirty_deriveds);
this.oncommit(() => batch.discard());
batch.#unlink();
@ -873,8 +806,7 @@ export class Batch {
effects[i],
this.#dirty_effects,
this.#maybe_dirty_effects,
this.#dirty_deriveds,
this.#maybe_dirty_deriveds
this.#dirty_deriveds
);
}
}
@ -903,22 +835,6 @@ export class Batch {
let batch = this.next;
let is_latest_value = !this.is_fork;
while (batch) {
// TODO this is obsolete through runtime.js logic?
if (source.f & ASYNC && false) {
// TODO I think this is wrong IF the async source was already written to by a later batch;
// we gotta check if it's the source is also part of the later batch.
const b = batch;
const run = () => {
if (b.mark(source, DIRTY)) {
b.flush();
}
};
if (this.is_fork) {
// this.on_fork_commit.set({}, run); // TODO done by mark in commit already?
} else {
queue_micro_task(run);
}
}
if (
!batch.is_fork &&
(!is_latest_value ||
@ -1262,9 +1178,8 @@ export class Batch {
* @param {Set<Effect>} dirty_effects
* @param {Set<Effect>} maybe_dirty_effects
* @param {Set<Derived>} dirty_deriveds
* @param {Set<Derived>} maybe_dirty_deriveds
*/
transfer_effects(dirty_effects, maybe_dirty_effects, dirty_deriveds, maybe_dirty_deriveds) {
transfer_effects(dirty_effects, maybe_dirty_effects, dirty_deriveds) {
for (const e of dirty_effects) {
this.#dirty_effects.add(e);
}
@ -1277,10 +1192,6 @@ export class Batch {
this.#dirty_deriveds.add(d);
}
for (const d of maybe_dirty_deriveds) {
this.#maybe_dirty_deriveds.add(d);
}
dirty_effects.clear();
maybe_dirty_effects.clear();
}
@ -1361,42 +1272,6 @@ export class Batch {
}
}
}
return;
// ...and undo changes belonging to other batches unless they intersect
for (let batch = first_batch; batch !== null; batch = batch.next) {
if (batch === this || batch.is_fork) continue;
// If two batches intersect, the latter batch will be merged into the earlier batch,
// and we should treat them as a single set of changes
var intersects = false;
if (batch.id < this.id) {
for (const [source, [, is_derived]] of batch.current) {
// Derived values don't partake in the intersection mechanism, because a derived could
// be triggered in one batch already but not the other one yet, causing a false-positive
if (is_derived) continue;
if (this.current.has(source)) {
intersects = true;
break;
}
}
}
// Since the latter batch merges into the earlier (if it resolves before the earlier one),
// we treat the earlier values as "already applied". This way we don't need to rerun async
// effects of the earlier batch in case they are merged.
// As a result you can think of batch_values as having the latest values of all intersecting
// batches up until this batch.
if (!intersects) {
for (const [source, previous] of batch.previous) {
if (!batch_values.has(source)) {
batch_values.set(source, previous);
}
}
}
}
}
/**
@ -1949,26 +1824,6 @@ export function fork(fn) {
next_batch = next_batch.next;
}
// let next_batch = batch.next;
// while (next_batch) {
// for (const [effect] of batch.async_deriveds) {
// if (next_batch.async_deriveds.has(effect)) {
// next_batch.dependent.add(batch);
// if (!next_batch.is_fork) {
// set_signal_status(effect, DIRTY); // TODO ideally we can find out if we really need to rerun or if all dependencies' values are equal
// // TODO same for block effects; ideally one mechanism for both
// next_batch.schedule(effect);
// const b = next_batch;
// queue_micro_task(() => b.flush());
// }
// }
// }
// next_batch = next_batch.next;
// }
// for (const run of batch.on_fork_commit.values()) {
// run();
// }
await settled;
},
discard: () => {

@ -7,15 +7,8 @@ import { set_signal_status } from './status.js';
* @param {Set<Effect>} dirty_effects
* @param {Set<Effect>} maybe_dirty_effects
* @param {Set<Derived>} dirty_deriveds
* @param {Set<Derived>} maybe_dirty_deriveds
*/
export function defer_effect(
effect,
dirty_effects,
maybe_dirty_effects,
dirty_deriveds,
maybe_dirty_deriveds
) {
export function defer_effect(effect, dirty_effects, maybe_dirty_effects, dirty_deriveds) {
if ((effect.f & DIRTY) !== 0) {
dirty_effects.add(effect);
} else if ((effect.f & MAYBE_DIRTY) !== 0) {
@ -28,16 +21,15 @@ export function defer_effect(
if (effect.deps === null) return;
for (const dep of effect.deps) {
defer_derived(dep, dirty_deriveds, maybe_dirty_deriveds);
defer_derived(dep, dirty_deriveds);
}
}
/**
* @param {Value} value
* @param {Set<Derived>} dirty_deriveds
* @param {Set<Derived>} maybe_dirty_deriveds
*/
function defer_derived(value, dirty_deriveds, maybe_dirty_deriveds) {
function defer_derived(value, dirty_deriveds) {
if ((value.f & DERIVED) === 0 || (value.f & CLEAN) !== 0) return;
var derived = /** @type {Derived} */ (value);
@ -45,16 +37,11 @@ function defer_derived(value, dirty_deriveds, maybe_dirty_deriveds) {
if ((derived.f & DIRTY) !== 0) {
dirty_deriveds.add(derived);
set_signal_status(derived, MAYBE_DIRTY);
} else if ((derived.f & MAYBE_DIRTY) !== 0) {
// maybe_dirty_deriveds.add(derived);
}
// mark as clean so they don't get rerun unnecessarily in other batches
// set_signal_status(derived, CLEAN);
if (derived.deps === null) return;
for (const dep of derived.deps) {
defer_derived(dep, dirty_deriveds, maybe_dirty_deriveds);
defer_derived(dep, dirty_deriveds);
}
}

Loading…
Cancel
Save