diff --git a/packages/svelte/src/index-client.js b/packages/svelte/src/index-client.js index ef6a24074c..dc892ef92d 100644 --- a/packages/svelte/src/index-client.js +++ b/packages/svelte/src/index-client.js @@ -219,4 +219,4 @@ export { getContext, getAllContexts, hasContext, setContext } from './internal/c export { hydrate, mount, unmount } from './internal/client/render.js'; export { tick, untrack } from './internal/client/runtime.js'; export { createRawSnippet } from './internal/client/dom/blocks/snippet.js'; -export { Resource, createResourceContext, deferPending } from './internal/client/reactivity/resources.js'; +export { Resource, createResourceContext } from './internal/client/reactivity/resources.js'; diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 3747840f0f..57ef5b6c14 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -12,7 +12,6 @@ import { import { active_reaction, active_effect, - remove_reactions, set_signal_status, skip_reaction, update_reaction, @@ -29,7 +28,6 @@ import { get_stack } from '../dev/tracing.js'; import { tracing_mode_flag } from '../../flags/index.js'; import { capture, suspend } from '../dom/blocks/boundary.js'; import { component_context } from '../context.js'; -import { noop } from '../../shared/utils.js'; import { UNINITIALIZED } from '../../../constants.js'; /** @type {Effect | null} */ @@ -73,7 +71,7 @@ export function derived(fn) { fn, reactions: null, rv: 0, - v: /** @type {V} */ (null), + v: /** @type {V} */ (UNINITIALIZED), wv: 0, parent: parent_derived ?? active_effect }; diff --git a/packages/svelte/src/internal/client/reactivity/resources.js b/packages/svelte/src/internal/client/reactivity/resources.js index 4092e723c1..519e50eaa1 100644 --- a/packages/svelte/src/internal/client/reactivity/resources.js +++ b/packages/svelte/src/internal/client/reactivity/resources.js @@ -4,7 +4,7 @@ import { UNINITIALIZED } from '../../../constants.js'; import { is_array } from '../../shared/utils.js'; import { EFFECT_PRESERVED } from '../constants.js'; import { getContext, setContext } from '../context.js'; -import { active_effect, get, handle_error, untrack } from '../runtime.js'; +import { active_effect, active_reaction, get, handle_error, untrack } from '../runtime.js'; import { derived } from './deriveds.js'; import { block } from './effects.js'; import { internal_set, source } from './sources.js'; @@ -44,7 +44,12 @@ export class Resource { get(this.#fn) .then( (value) => { - if (current_token !== token) return; + if (current_token !== token) { + if (this.#current.v === UNINITIALIZED) { + internal_set(this.#current, value); + } + return; + } internal_set(this.#current, value); internal_set(this.#pending, false); return value; @@ -65,6 +70,10 @@ export class Resource { return get(this.#pending); } + get latest() { + return get(this.#fn); + } + get current() { var value = get(this.#current); @@ -76,23 +85,54 @@ export class Resource { } /** - * @param {(arg0: { readonly current: T; readonly latest: T; }) => void} onfulfilled + * @param {(arg0: boolean) => void} onfulfilled * @param {((reason: any) => PromiseLike) | null | undefined} onrejected */ then(onfulfilled, onrejected) { - return get(this.#fn).then(() => { - var self = this; - onfulfilled({ - get current() { - return get(self.#current); - }, - get latest() { - get(self.#fn); - return get(self.#current); - } - }); + return this.#fn.v.then(() => { + onfulfilled(true); }, onrejected); } + + /** + * @template T, V + * @param {Resource | Resource[]} resources + * @param {() => V} fn + */ + static deferred(resources, fn) { + const res = is_array(resources) ? resources : [resources]; + + var deferred = derived(() => { + var prev = /** @type {Derived} */ (active_reaction)?.v; + + for (let i = 0; i < res.length; i += 1) { + const resource = res[i]; + const pending = untrack(() => resource.pending); + + try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + resource.current; + } catch { + // NOOP + } + if (pending) { + if (prev !== UNINITIALIZED) { + return prev; + } + return untrack(fn); + } + } + return fn(); + }); + + get(deferred); + + return { + get current() { + return get(deferred); + } + }; + } } /** @@ -122,23 +162,3 @@ export function createResourceContext() { return [set_resource, get_resource]; } - -/** - * @template T, V - * @param {Resource | Resource[]} resources - * @param {() => V} fn - */ -export function deferPending(resources, fn) { - const res = is_array(resources) ? resources : [resources]; - - for (let i = 0; i < res.length; i += 1) { - const resource = res[i]; - const pending = untrack(() => resource.pending); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - resource.current; - if (pending) { - break; - } - } - return untrack(fn); -}