object-blockers
Rich Harris 6 months ago
parent e69bf8dbce
commit e44374f208

@ -112,7 +112,9 @@ function add_const_declaration(state, id, expression, metadata, bindings) {
const assignment = b.assignment('=', id, expression);
const body = after.length === 0 ? assignment : b.block([b.stmt(assignment), ...after]);
if (blockers.length > 0) run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
if (blockers.length > 0) {
run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
}
run.thunks.push(b.thunk(body, has_await));

@ -1,4 +1,4 @@
/** @import { TemplateNode, Value } from '#client' */
/** @import { Blocker, TemplateNode, Value } from '#client' */
import { flatten, is_promise_settled } from '../../reactivity/async.js';
import { Batch, current_batch } from '../../reactivity/batch.js';
import { get } from '../../runtime.js';
@ -14,12 +14,12 @@ import { get_boundary } from './boundary.js';
/**
* @param {TemplateNode} node
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
* @param {Array<() => Promise<any>>} expressions
* @param {(anchor: TemplateNode, ...deriveds: Value[]) => void} fn
*/
export function async(node, blockers = [], expressions = [], fn) {
if (expressions.length === 0 && blockers.length > 0 && blockers.every(is_promise_settled)) {
if (expressions.length === 0 && blockers.every((b) => b.settled)) {
fn(node);
return;
}

@ -1,4 +1,4 @@
/** @import { Effect } from '#client' */
/** @import { Blocker, Effect } from '#client' */
import { DEV } from 'esm-env';
import { hydrating, set_hydrating } from '../hydration.js';
import { get_descriptors, get_prototype_of } from '../../../shared/utils.js';
@ -483,7 +483,7 @@ function set_attributes(
* @param {(...expressions: any) => Record<string | symbol, any>} fn
* @param {Array<() => any>} sync
* @param {Array<() => Promise<any>>} async
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
* @param {string} [css_hash]
* @param {boolean} [should_remove_defaults]
* @param {boolean} [skip_warning]

@ -1,5 +1,4 @@
/** @import { Effect, TemplateNode, Value } from '#client' */
/** @import { Blocker, Effect, Value } from '#client' */
import { DESTROYED, STALE_REACTION } from '#client/constants';
import { DEV } from 'esm-env';
import {
@ -36,7 +35,7 @@ export function is_promise_settled(promise) {
}
/**
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
* @param {Array<() => any>} sync
* @param {Array<() => Promise<any>>} async
* @param {(values: Value[]) => any} fn
@ -45,7 +44,7 @@ export function flatten(blockers, sync, async, fn) {
const d = is_runes() ? derived : derived_safe_equal;
// Filter out already-settled blockers - no need to wait for them
var pending = blockers.filter((b) => !is_promise_settled(b));
var pending = blockers.filter((b) => !b.settled);
if (async.length === 0 && pending.length === 0) {
fn(sync.map(d));
@ -57,7 +56,11 @@ export function flatten(blockers, sync, async, fn) {
var restore = capture();
var blocker_promise =
pending.length === 1 ? pending[0] : pending.length > 1 ? Promise.all(pending) : null;
pending.length === 1
? pending[0].promise
: pending.length > 1
? Promise.all(pending.map((b) => b.promise))
: null;
/** @param {Value[]} values */
function finish(values) {
@ -97,7 +100,7 @@ export function flatten(blockers, sync, async, fn) {
}
/**
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
* @param {(values: Value[]) => any} fn
*/
export function run_after_blockers(blockers, fn) {
@ -252,13 +255,14 @@ export function run(thunks) {
var promise = Promise.resolve(thunks[0]()).catch(handle_error);
/** @type {Blocker} */
var blocker = { promise, settled: false };
var blockers = [blocker];
promise.finally(() => {
settled_promises.add(promise);
blocker.settled = true;
});
/** @type {Array<Promise<void>>} */
var promises = [promise];
for (const fn of thunks.slice(1)) {
promise = promise
.then(() => {
@ -275,16 +279,15 @@ export function run(thunks) {
})
.catch(handle_error);
const p = promise;
const blocker = { promise, settled: false };
blockers.push(blocker);
p.finally(() => {
settled_promises.add(p);
promise.finally(() => {
blocker.settled = true;
unset_context();
current_batch?.deactivate();
});
promises.push(p);
}
promise
@ -296,5 +299,12 @@ export function run(thunks) {
batch.decrement(blocking);
});
return promises;
return blockers;
}
/**
* @param {Blocker[]} blockers
*/
export function wait(blockers) {
return Promise.all(blockers.map((b) => b.promise));
}

@ -1,4 +1,4 @@
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
/** @import { Blocker, ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
import {
is_dirty,
active_effect,
@ -361,7 +361,7 @@ export function render_effect(fn, flags = 0) {
* @param {(...expressions: any) => void | (() => void)} fn
* @param {Array<() => any>} sync
* @param {Array<() => Promise<any>>} async
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
*/
export function template_effect(fn, sync = [], async = [], blockers = []) {
flatten(blockers, sync, async, (values) => {
@ -374,7 +374,7 @@ export function template_effect(fn, sync = [], async = [], blockers = []) {
* @param {(...expressions: any) => void | (() => void)} fn
* @param {Array<() => any>} sync
* @param {Array<() => Promise<any>>} async
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
*/
export function deferred_template_effect(fn, sync = [], async = [], blockers = []) {
var batch = /** @type {Batch} */ (current_batch);

@ -103,3 +103,8 @@ export interface Effect extends Reaction {
export type Source<V = unknown> = Value<V>;
export type MaybeSource<T = unknown> = T | Source<T>;
export interface Blocker {
promise: Promise<any>;
settled: boolean;
}

@ -1,3 +1,4 @@
/** @import { Blocker } from '#client' */
import { dev_current_component_function } from './context.js';
import { is_array } from '../shared/utils.js';
import * as e from './errors.js';
@ -41,7 +42,7 @@ export function validate_each_keys(collection, key_fn) {
/**
* @param {string} binding
* @param {Array<Promise<void>>} blockers
* @param {Blocker[]} blockers
* @param {() => Record<string, any>} get_object
* @param {() => string} get_property
* @param {number} line

Loading…
Cancel
Save