aa-coordination
Rich Harris 8 months ago
parent 2b0812817c
commit 41314a685a

@ -33,6 +33,7 @@ import * as e from '../../../shared/errors.js';
const ASYNC_INCREMENT = Symbol();
const ASYNC_DECREMENT = Symbol();
const ADD_CALLBACK = Symbol();
/**
* @param {Effect} boundary
@ -88,6 +89,9 @@ export function boundary(node, props, children) {
var hydrate_open = hydrate_node;
var is_creating_fallback = false;
/** @type {Function[]} */
var callbacks = [];
/**
* @param {() => void} snippet_fn
* @returns {Effect | null}
@ -108,48 +112,6 @@ export function boundary(node, props, children) {
});
}
function suspend() {
if (offscreen_fragment || !main_effect) {
return;
}
var effect = main_effect;
pause_effect(
effect,
() => {
offscreen_fragment = document.createDocumentFragment();
move_effect(effect, offscreen_fragment);
},
false
);
const pending = props.pending;
if (pending) {
pending_effect = render_snippet(() => pending(anchor));
}
}
function unsuspend() {
if (!offscreen_fragment) {
return;
}
if (pending_effect !== null) {
pause_effect(pending_effect, () => {
pending_effect = null;
});
}
anchor.before(/** @type {DocumentFragment} */ (offscreen_fragment));
offscreen_fragment = null;
if (main_effect !== null) {
resume_effect(main_effect);
}
}
function reset() {
if (failed_effect !== null) {
pause_effect(failed_effect, () => {
@ -169,7 +131,7 @@ export function boundary(node, props, children) {
}
// @ts-ignore We re-use the effect's fn property to avoid allocation of an additional field
boundary.fn = (/** @type {unknown} */ input) => {
boundary.fn = (/** @type {unknown} */ input, /** @type {Function} */ payload) => {
if (input === ASYNC_INCREMENT) {
async_count++;
@ -182,6 +144,12 @@ export function boundary(node, props, children) {
if (--async_count === 0) {
boundary.f ^= BOUNDARY_SUSPENDED;
for (const callback of callbacks) {
callback();
}
callbacks.length = 0;
if (pending_effect) {
pause_effect(pending_effect, () => {
pending_effect = null;
@ -202,6 +170,11 @@ export function boundary(node, props, children) {
return;
}
if (input === ADD_CALLBACK) {
callbacks.push(payload);
return;
}
var error = input;
var onerror = props.onerror;
let failed = props.failed;
@ -377,3 +350,27 @@ function exit() {
set_active_reaction(null);
set_component_context(null);
}
/**
* @param {Effect | null} effect
*/
export function find_boundary(effect) {
while (effect !== null && (effect.f & BOUNDARY_EFFECT) === 0) {
effect = effect.parent;
}
return effect;
}
/**
* @param {Effect | null} boundary
* @param {Function} fn
*/
export function add_boundary_callback(boundary, fn) {
if (boundary === null) {
throw new Error('TODO');
}
// @ts-ignore
boundary.fn(ADD_CALLBACK, fn);
}

@ -10,6 +10,8 @@ import {
} from '../hydration.js';
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
import { HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js';
import { active_effect, suspended } from '../../runtime.js';
import { add_boundary_callback, find_boundary } from './boundary.js';
/**
* @param {TemplateNode} node
@ -42,6 +44,46 @@ export function if_block(node, fn, elseif = false) {
update_branch(flag, fn);
};
/** @type {DocumentFragment | null} */
var offscreen_fragment = null;
/** @type {Effect | null} */
var pending_effect = null;
var boundary = find_boundary(active_effect);
function commit() {
if (offscreen_fragment !== null) {
anchor.before(offscreen_fragment);
offscreen_fragment = null;
}
if (condition) {
consequent_effect = pending_effect;
} else {
alternate_effect = pending_effect;
}
var current_effect = condition ? consequent_effect : alternate_effect;
var previous_effect = condition ? alternate_effect : consequent_effect;
if (current_effect !== null) {
resume_effect(current_effect);
}
if (previous_effect !== null) {
pause_effect(previous_effect, () => {
if (condition) {
alternate_effect = null;
} else {
consequent_effect = null;
}
});
}
pending_effect = null;
}
const update_branch = (
/** @type {boolean | null} */ new_condition,
/** @type {null | ((anchor: Node) => void)} */ fn
@ -65,30 +107,19 @@ export function if_block(node, fn, elseif = false) {
}
}
if (condition) {
if (consequent_effect) {
resume_effect(consequent_effect);
} else if (fn) {
consequent_effect = branch(() => fn(anchor));
}
var target = anchor;
if (alternate_effect) {
pause_effect(alternate_effect, () => {
alternate_effect = null;
});
}
} else {
if (alternate_effect) {
resume_effect(alternate_effect);
} else if (fn) {
alternate_effect = branch(() => fn(anchor));
}
if (suspended) {
offscreen_fragment = document.createDocumentFragment();
offscreen_fragment.append((target = document.createComment('')));
}
if (consequent_effect) {
pause_effect(consequent_effect, () => {
consequent_effect = null;
});
}
pending_effect = fn && branch(() => fn(target));
if (suspended) {
add_boundary_callback(boundary, commit);
} else {
commit();
}
if (mismatch) {

@ -567,20 +567,15 @@ export function unlink_effect(effect) {
* A paused effect does not update, and the DOM subtree becomes inert.
* @param {Effect} effect
* @param {() => void} [callback]
* @param {boolean} [destroy]
*/
export function pause_effect(effect, callback, destroy = true) {
export function pause_effect(effect, callback) {
/** @type {TransitionManager[]} */
var transitions = [];
pause_children(effect, transitions, true);
run_out_transitions(transitions, () => {
if (destroy) {
destroy_effect(effect);
} else {
execute_effect_teardown(effect);
}
destroy_effect(effect);
if (callback) callback();
});
}

@ -27,7 +27,6 @@ import {
DISCONNECTED,
BOUNDARY_EFFECT,
REACTION_IS_UPDATING,
IS_ASYNC,
TEMPLATE_EFFECT,
BOUNDARY_SUSPENDED
} from './constants.js';
@ -44,7 +43,6 @@ import { lifecycle_outside_component } from '../shared/errors.js';
import { FILENAME } from '../../constants.js';
import { legacy_mode_flag, tracing_mode_flag } from '../flags/index.js';
import { tracing_expressions, get_stack } from './dev/tracing.js';
import { is_pending_boundary } from './dom/blocks/boundary.js';
const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
@ -89,6 +87,8 @@ export let active_reaction = null;
export let untracking = false;
export let suspended = false;
/** @param {null | Reaction} reaction */
export function set_active_reaction(reaction) {
active_reaction = reaction;
@ -826,7 +826,7 @@ export function schedule_effect(signal) {
function process_effects(effect, collected_effects) {
var current_effect = effect.first;
var effects = [];
var suspended = false;
suspended = false;
main_loop: while (current_effect !== null) {
var flags = current_effect.f;

Loading…
Cancel
Save