async-fork
Dominic Gannaway 7 months ago
parent 044475de01
commit 84b6ad7228

@ -18,7 +18,8 @@ import {
set_active_effect,
set_active_reaction,
reset_is_throwing_error,
schedule_effect
schedule_effect,
increment_write_version
} from '../../runtime.js';
import {
hydrate_next,
@ -170,11 +171,8 @@ export function boundary(node, props, children) {
for (var [signal, entry] of forks) {
if (signal.v !== entry.v) {
if ((signal.f & DERIVED) === 0) {
var val = signal.v;
signal.v = entry.v;
internal_set(signal, val);
} else {
mark_reactions(signal, DIRTY);
mark_reactions(signal, DIRTY, undefined, true);
signal.wv = increment_write_version();
}
}
}

@ -28,12 +28,14 @@ import {
UNOWNED,
MAYBE_DIRTY,
BLOCK_EFFECT,
ROOT_EFFECT
ROOT_EFFECT,
ASYNC_DERIVED
} from '../constants.js';
import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack } from '../dev/tracing.js';
import { component_context, is_runes } from '../context.js';
import { get_boundary } from '../dom/blocks/boundary.js';
export let inspect_effects = new Set();
@ -169,6 +171,7 @@ export function set(source, value) {
*/
export function internal_set(source, value) {
if (!source.equals(value)) {
possibly_fork(source);
mark_reactions(source, DIRTY);
@ -258,9 +261,10 @@ export function update_pre(source, d = 1) {
/**
* @param {Value} signal
* @param {number} status should be DIRTY or MAYBE_DIRTY
* @param {Value} [parent]
* @returns {void}
*/
export function mark_reactions(signal, status) {
export function mark_reactions(signal, status, parent, only_boundary = false) {
var reactions = signal.reactions;
if (reactions === null) return;
@ -277,6 +281,24 @@ export function mark_reactions(signal, status) {
// In legacy mode, skip the current effect to prevent infinite loops
if (!runes && reaction === active_effect) continue;
if (only_boundary) {
if ((flags & (DERIVED)) === 0) {
var boundary = get_boundary(/** @type {Effect} */ (reaction));
if (!boundary) {
continue;
}
}
} else if ((flags & (DERIVED | ASYNC_DERIVED)) === 0) {
boundary = get_boundary(/** @type {Effect} */ (reaction));
if (boundary) {
// @ts-ignore
var forks = boundary.fn.forks;
if (forks.has(signal) || forks.has(parent)) {
continue;
}
}
}
// Inspect effects need to run immediately, so that the stack trace makes sense
if (DEV && (flags & INSPECT_EFFECT) !== 0) {
inspect_effects.add(reaction);
@ -288,10 +310,76 @@ export function mark_reactions(signal, status) {
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ((flags & (CLEAN | UNOWNED)) !== 0) {
if ((flags & DERIVED) !== 0) {
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY, signal, only_boundary);
} else {
schedule_effect(/** @type {Effect} */ (reaction));
}
}
}
}
/**
* @param {Source | Derived} signal
* @param {any} forks
*/
function fork_dependencies(signal, forks) {
var entry = forks.get(signal);
if (entry === undefined) {
entry = { v: signal.v };
forks.set(signal, entry);
if ((signal.f & DERIVED) !== 0) {
var deps = /** @type {Derived} */ (signal).deps;
if (deps !== null) {
for (var i = 0; i < deps.length; i++) {
fork_dependencies(deps[i], forks);
}
}
}
}
}
/**
* @param {Value} signal
* @returns {void}
*/
function possibly_fork(signal) {
var reactions = signal.reactions;
if (reactions === null) return;
var runes = is_runes();
var length = reactions.length;
for (var i = 0; i < length; i++) {
var reaction = reactions[i];
var flags = reaction.f;
// Skip any effects that are already dirty
if ((flags & DIRTY) !== 0) continue;
// In legacy mode, skip the current effect to prevent infinite loops
if (!runes && reaction === active_effect) continue;
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ((flags & (CLEAN | UNOWNED)) !== 0) {
if ((flags & DERIVED) !== 0) {
possibly_fork(/** @type {Derived} */ (reaction));
} else {
if ((reaction.f & ASYNC_DERIVED) !== 0) {
// if (active_effect === signal) {
// set_signal_status(signal, MAYBE_DIRTY);
// return;
// }
var boundary = get_boundary(/** @type {Effect} */ (reaction));
// @ts-ignore
var forks = boundary.fn.forks;
var deps = reaction.deps;
if (deps !== null) {
for (var s = 0; s < deps.length; s++) {
fork_dependencies(deps[s], forks);
}
}
}
}
}
}
}

@ -783,47 +783,11 @@ function flush_deferred() {
}
}
/**
* @param {Source | Derived} signal
* @param {any} forks
*/
function fork_dependencies(signal, forks) {
var entry = forks.get(signal);
if (entry === undefined) {
entry = { v: signal.v };
forks.set(signal, entry);
if ((signal.f & DERIVED) !== 0) {
var deps = /** @type {Derived} */ (signal).deps;
if (deps !== null) {
for (var i = 0; i < deps.length; i++) {
fork_dependencies(deps[i], forks);
}
}
}
}
}
/**
* @param {Effect} signal
* @returns {void}
*/
export function schedule_effect(signal) {
if ((signal.f & ASYNC_DERIVED) !== 0) {
if (active_effect === signal) {
set_signal_status(signal, MAYBE_DIRTY);
return;
}
var boundary = get_boundary(signal);
// @ts-ignore
var forks = boundary.fn.forks;
var deps = signal.deps;
if (deps !== null) {
for (var i = 0; i < deps.length; i++) {
fork_dependencies(deps[i], forks);
}
}
}
if (scheduler_mode === FLUSH_MICROTASK) {
if (!is_micro_task_queued) {
is_micro_task_queued = true;
@ -1067,7 +1031,11 @@ export function get(signal) {
var target_effect = event_boundary_effect ?? active_effect;
if (target_effect !== null && !is_flushing_async_derived) {
if (
target_effect !== null &&
!is_flushing_async_derived &&
(target_effect.f & ASYNC_DERIVED) === 0
) {
var boundary = get_boundary(target_effect);
if (boundary !== null) {
// @ts-ignore

@ -32,11 +32,7 @@ export default test({
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await tick();
flushSync();
assert.htmlEqual(target.innerHTML, '<p>84</p>');
d = deferred();

Loading…
Cancel
Save