Skip to content

Commit ba5d219

Browse files
committed
add resource
1 parent e69d85b commit ba5d219

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

packages/svelte/src/index-client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,4 @@ export { getContext, getAllContexts, hasContext, setContext } from './internal/c
219219
export { hydrate, mount, unmount } from './internal/client/render.js';
220220
export { tick, untrack } from './internal/client/runtime.js';
221221
export { createRawSnippet } from './internal/client/dom/blocks/snippet.js';
222+
export { Resource } from './internal/client/reactivity/resources.js';

packages/svelte/src/internal/client/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const EFFECT_PRESERVED = 1 << 21; // effects with this flag should not be
2424
// Flags used for async
2525
export const REACTION_IS_UPDATING = 1 << 22;
2626
export const BOUNDARY_SUSPENDED = 1 << 23;
27+
export const IS_PENDING = 1 << 24;
2728

2829
export const STATE_SYMBOL = Symbol('$state');
2930
export const STATE_SYMBOL_METADATA = Symbol('$state metadata');
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/** @import { Derived, Effect, Source } from '#client' */
2+
3+
import { UNINITIALIZED } from '../../../constants';
4+
import { EFFECT_PRESERVED, IS_PENDING } from '../constants';
5+
import { active_effect, captured_signals, get, handle_error } from '../runtime';
6+
import { derived } from './deriveds';
7+
import { block } from './effects';
8+
import { internal_set, source } from './sources';
9+
10+
/**
11+
* @template T
12+
*/
13+
export class Resource {
14+
/** @type {Source<T>} */
15+
#current = source(/** @type {T} */ (UNINITIALIZED));
16+
/** @type {Derived<Promise<T>>} */
17+
#fn;
18+
/** @type {Source<boolean>} */
19+
#pending = source(true);
20+
21+
/** @param {() => Promise<T>} fn */
22+
constructor(fn) {
23+
let parent = /** @type {Effect | null} */ (active_effect);
24+
25+
if (parent === null) {
26+
throw new Error('TODO cannot create resources outside of an effect');
27+
}
28+
29+
/** @type {{}} */
30+
var current_token;
31+
32+
this.#current.f ^= IS_PENDING;
33+
this.#fn = derived(() => Promise.resolve(fn()));
34+
35+
block(() => {
36+
var current = this.#current;
37+
if ((current.f & IS_PENDING) === 0) {
38+
current.f ^= IS_PENDING;
39+
}
40+
var token = (current_token = {});
41+
internal_set(this.#pending, true);
42+
43+
get(this.#fn).then(
44+
(value) => {
45+
if (current_token !== token) return;
46+
internal_set(this.#current, value);
47+
internal_set(this.#pending, false);
48+
this.#current.f ^= IS_PENDING;
49+
return value;
50+
},
51+
(error) => {
52+
if (current_token !== token) return;
53+
internal_set(this.#pending, false);
54+
throw error;
55+
}
56+
).catch((e) => {
57+
handle_error(e, parent, null, parent.ctx);
58+
});
59+
}, EFFECT_PRESERVED);
60+
}
61+
62+
get pending() {
63+
return get(this.#pending);
64+
}
65+
66+
get current() {
67+
var value = get(this.#current);
68+
69+
if (captured_signals !== null) {
70+
get(this.#fn);
71+
}
72+
73+
if (value === UNINITIALIZED) {
74+
return this.#fn.v;
75+
}
76+
77+
return value;
78+
}
79+
80+
get latest() {
81+
var current = this.#current;
82+
var value = get(current);
83+
var promise = get(this.#fn);
84+
85+
if ((current.f & IS_PENDING) === 0) {
86+
return value;
87+
}
88+
89+
return promise;
90+
}
91+
}

packages/svelte/src/internal/client/runtime.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ export function capture_signals(fn) {
10921092
var signal;
10931093

10941094
try {
1095-
untrack(fn);
1095+
fn();
10961096
if (previous_captured_signals !== null) {
10971097
for (signal of captured_signals) {
10981098
previous_captured_signals.add(signal);

packages/svelte/types/index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,15 @@ declare module 'svelte' {
512512
* ```
513513
* */
514514
export function untrack<T>(fn: () => T): T;
515+
export function isPending(fn: () => any): boolean;
516+
517+
export class Resource<T> {
518+
519+
constructor(fn: () => Promise<T>);
520+
get current(): T | Promise<Awaited<T>>;
521+
get latest(): T | Promise<Awaited<T>>;
522+
#private;
523+
}
515524
type Getters<T> = {
516525
[K in keyof T]: () => T[K];
517526
};

0 commit comments

Comments
 (0)