unified-async
Rich Harris 5 months ago
parent 60c99dfc51
commit ff803ccaa9

@ -1,6 +1,8 @@
/** @import { Effect, Source, TemplateNode, } from '#client' */
import {
BOUNDARY_EFFECT,
BRANCH_EFFECT,
CLEAN,
COMMENT_NODE,
DIRTY,
EFFECT_PRESERVED,
@ -202,7 +204,7 @@ export class Boundary {
this.#pending_effect = null;
});
this.is_pending = false;
this.#resolve();
}
});
}
@ -224,13 +226,36 @@ export class Boundary {
const pending = /** @type {(anchor: Node) => void} */ (this.#props.pending);
this.#pending_effect = branch(() => pending(this.#anchor));
} else {
this.is_pending = false;
this.#resolve();
}
} catch (error) {
this.error(error);
}
}
#resolve() {
this.is_pending = false;
reset_branch(/** @type {Effect} */ (this.#main_effect));
// any effects that were encountered and deferred during traversal
// should be rescheduled — after the next traversal (which will happen
// immediately, due to the same update that brought us here)
// the effects will be flushed
for (const e of this.#dirty_effects) {
set_signal_status(e, DIRTY);
schedule_effect(e);
}
for (const e of this.#maybe_dirty_effects) {
set_signal_status(e, MAYBE_DIRTY);
schedule_effect(e);
}
this.#dirty_effects.clear();
this.#maybe_dirty_effects.clear();
}
/**
* Defer an effect inside a pending boundary until the boundary resolves
* @param {Effect} effect
@ -294,24 +319,7 @@ export class Boundary {
this.#pending_count += d;
if (this.#pending_count === 0) {
this.is_pending = false;
// any effects that were encountered and deferred during traversal
// should be rescheduled — after the next traversal (which will happen
// immediately, due to the same update that brought us here)
// the effects will be flushed
for (const e of this.#dirty_effects) {
set_signal_status(e, DIRTY);
schedule_effect(e);
}
for (const e of this.#maybe_dirty_effects) {
set_signal_status(e, MAYBE_DIRTY);
schedule_effect(e);
}
this.#dirty_effects.clear();
this.#maybe_dirty_effects.clear();
this.#resolve();
if (this.#pending_effect) {
pause_effect(this.#pending_effect, () => {
@ -465,3 +473,25 @@ export function pending() {
return boundary.get_effect_pending();
}
/**
* TODO remove this - when we fully switch to a lazy scheduling approach,
* we won't have dirtied the branches in the first place. But for now
* it is necessary to keep the tests passing
* @param {Effect} effect
* @deprecated
*/
function reset_branch(effect) {
// clean branch = nothing dirty inside, no need to traverse further
if ((effect.f & BRANCH_EFFECT) !== 0 && (effect.f & CLEAN) !== 0) {
return;
}
set_signal_status(effect, CLEAN);
var e = effect.first;
while (e !== null) {
reset_branch(e);
e = e.next;
}
}

@ -859,6 +859,15 @@ export function schedule_effect(signal) {
if ((flags & CLEAN) === 0) return;
effect.f ^= CLEAN;
}
if ((flags & BOUNDARY_EFFECT) !== 0) {
var boundary = /** @type {Boundary} */ (effect.b);
if (boundary.is_pending && ((signal.f & (EFFECT | RENDER_EFFECT | MANAGED_EFFECT)) !== 0)) {
boundary.defer_effect(signal);
return;
}
}
}
queued_root_effects.push(effect);

Loading…
Cancel
Save