non-working possible alterative to #16621

boundary-batch-nullpointer-fix-alt
Rich Harris 6 days ago
parent b88b4e8ef8
commit 2b7c9a8a21

@ -177,14 +177,6 @@ export class Batch {
/** @type {Map<Source, { v: unknown, wv: number }> | null} */ /** @type {Map<Source, { v: unknown, wv: number }> | null} */
var current_values = null; var current_values = null;
/**
* A batch is superseded if all of its sources are also in the current batch.
* If the current batch commits, we don't need the old batch anymore.
* This also prevents memory leaks since the old batch will never be committed.
* @type {Batch[]}
*/
var superseded_batches = [];
// if there are multiple batches, we are 'time travelling' — // if there are multiple batches, we are 'time travelling' —
// we need to undo the changes belonging to any batch // we need to undo the changes belonging to any batch
// other than the current one // other than the current one
@ -197,25 +189,17 @@ export class Batch {
source.v = current; source.v = current;
} }
let is_prior_batch = true;
for (const batch of batches) { for (const batch of batches) {
if (batch === this) { if (batch === this) {
is_prior_batch = false;
continue; continue;
} }
let superseded = is_prior_batch;
for (const [source, previous] of batch.#previous) { for (const [source, previous] of batch.#previous) {
if (!current_values.has(source)) { if (!current_values.has(source)) {
superseded = false;
current_values.set(source, { v: source.v, wv: source.wv }); current_values.set(source, { v: source.v, wv: source.wv });
source.v = previous; source.v = previous;
} }
} }
if (superseded) superseded_batches.push(batch);
} }
} }
@ -226,21 +210,21 @@ export class Batch {
// if we didn't start any new async work, and no async work // if we didn't start any new async work, and no async work
// is outstanding from a previous flush, commit // is outstanding from a previous flush, commit
if (this.#async_effects.length === 0 && this.#pending === 0) { if (this.#async_effects.length === 0 && this.#pending === 0) {
if (superseded_batches.length > 0) { for (const batch of batches) {
const own = [...this.#callbacks.keys()]; if (batch === this) break;
// A superseded batch could have callbacks for e.g. destroying if blocks
// that are not part of the current batch because it already happened in the prior one, for (const effects of [batch.#dirty_effects, batch.#maybe_dirty_effects]) {
// and the corresponding block effect therefore returning early because nothing was changed from its let i = effects.length;
// point of view, therefore not adding a callback to the current batch, so we gotta call them here. while (i--) {
// We do it from newest to oldest to ensure the correct callback is applied. // if an effect in an earlier batch only depends on state that
for (const batch of superseded_batches.reverse()) { // is part of this batch, we can delete it from the other batch
for (const [effect, cb] of batch.#callbacks) { const effect = effects[i];
if (!own.includes(effect)) { const has_other_deps = effect.deps?.some((value) => !this.current.has(value));
cb();
own.push(effect); if (!has_other_deps) {
effects.splice(i, 1); // TODO should probably be a `Set` if we're going to do this
} }
} }
batch.remove();
} }
} }

Loading…
Cancel
Save