mirror of https://github.com/sveltejs/svelte
parent
e69d85b1a0
commit
ba5d219a53
@ -0,0 +1,91 @@
|
||||
/** @import { Derived, Effect, Source } from '#client' */
|
||||
|
||||
import { UNINITIALIZED } from '../../../constants';
|
||||
import { EFFECT_PRESERVED, IS_PENDING } from '../constants';
|
||||
import { active_effect, captured_signals, get, handle_error } from '../runtime';
|
||||
import { derived } from './deriveds';
|
||||
import { block } from './effects';
|
||||
import { internal_set, source } from './sources';
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
export class Resource {
|
||||
/** @type {Source<T>} */
|
||||
#current = source(/** @type {T} */ (UNINITIALIZED));
|
||||
/** @type {Derived<Promise<T>>} */
|
||||
#fn;
|
||||
/** @type {Source<boolean>} */
|
||||
#pending = source(true);
|
||||
|
||||
/** @param {() => Promise<T>} fn */
|
||||
constructor(fn) {
|
||||
let parent = /** @type {Effect | null} */ (active_effect);
|
||||
|
||||
if (parent === null) {
|
||||
throw new Error('TODO cannot create resources outside of an effect');
|
||||
}
|
||||
|
||||
/** @type {{}} */
|
||||
var current_token;
|
||||
|
||||
this.#current.f ^= IS_PENDING;
|
||||
this.#fn = derived(() => Promise.resolve(fn()));
|
||||
|
||||
block(() => {
|
||||
var current = this.#current;
|
||||
if ((current.f & IS_PENDING) === 0) {
|
||||
current.f ^= IS_PENDING;
|
||||
}
|
||||
var token = (current_token = {});
|
||||
internal_set(this.#pending, true);
|
||||
|
||||
get(this.#fn).then(
|
||||
(value) => {
|
||||
if (current_token !== token) return;
|
||||
internal_set(this.#current, value);
|
||||
internal_set(this.#pending, false);
|
||||
this.#current.f ^= IS_PENDING;
|
||||
return value;
|
||||
},
|
||||
(error) => {
|
||||
if (current_token !== token) return;
|
||||
internal_set(this.#pending, false);
|
||||
throw error;
|
||||
}
|
||||
).catch((e) => {
|
||||
handle_error(e, parent, null, parent.ctx);
|
||||
});
|
||||
}, EFFECT_PRESERVED);
|
||||
}
|
||||
|
||||
get pending() {
|
||||
return get(this.#pending);
|
||||
}
|
||||
|
||||
get current() {
|
||||
var value = get(this.#current);
|
||||
|
||||
if (captured_signals !== null) {
|
||||
get(this.#fn);
|
||||
}
|
||||
|
||||
if (value === UNINITIALIZED) {
|
||||
return this.#fn.v;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
get latest() {
|
||||
var current = this.#current;
|
||||
var value = get(current);
|
||||
var promise = get(this.#fn);
|
||||
|
||||
if ((current.f & IS_PENDING) === 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
}
|
Loading…
Reference in new issue