add getAbortSignal

async-abort-signal
Rich Harris 7 months ago
parent 726b3f1b85
commit 39179583c4

@ -216,6 +216,7 @@ export function flushSync(fn) {
}
export { getContext, getAllContexts, hasContext, setContext } from './internal/client/context.js';
export { getAbortSignal } from './internal/client/reactivity/abort-signal.js';
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';

@ -19,7 +19,9 @@ import {
reset_is_throwing_error,
schedule_effect,
check_dirtiness,
update_effect
update_effect,
invocation_version,
set_invocation_version
} from '../../runtime.js';
import {
hydrate_next,
@ -405,6 +407,7 @@ export function capture(track = true) {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
var previous_component_context = component_context;
var previous_invocation_version = invocation_version;
if (DEV && !track) {
var was_from_async_derived = from_async_derived;
@ -415,6 +418,7 @@ export function capture(track = true) {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
set_component_context(previous_component_context);
set_invocation_version(invocation_version);
} else if (DEV) {
set_from_async_derived(was_from_async_derived);
}

@ -0,0 +1,15 @@
import { active_reaction, invocation_version } from '../runtime.js';
export function getAbortSignal() {
if (active_reaction === null) {
throw new Error('TODO');
}
var controller = (active_reaction.ctrl ??= new AbortController());
if (active_reaction.iv > invocation_version) {
controller.abort();
}
return controller.signal;
}

@ -115,7 +115,9 @@ function create_effect(type, fn, sync, push = true) {
prev: null,
teardown: null,
transitions: null,
wv: 0
wv: 0,
iv: 0,
ctrl: null
};
if (DEV) {

@ -31,6 +31,10 @@ export interface Reaction extends Signal {
fn: null | Function;
/** Signals that this signal reads from */
deps: null | Value[];
/** Invocation version, so we can know if we're in a reaction that was already invalidated */
iv: number;
/** AbortController */
ctrl: AbortController | null;
}
export interface Derived<V = unknown> extends Value<V>, Reaction {

@ -109,6 +109,13 @@ export function set_active_effect(effect) {
active_effect = effect;
}
export let invocation_version = 0;
/** @param {number} v */
export function set_invocation_version(v) {
invocation_version = v;
}
// TODO remove this, once we're satisfied that we're not leaking context
/* @__PURE__ */
setInterval(() => {
@ -444,9 +451,13 @@ export function update_reaction(reaction) {
set_component_context(reaction.ctx);
untracking = false;
read_version++;
invocation_version = ++reaction.iv;
try {
reaction.f |= REACTION_IS_UPDATING;
reaction.ctrl?.abort();
reaction.ctrl = null;
var result = /** @type {Function} */ (0, reaction.fn)();
var deps = reaction.deps;

@ -1,5 +1,5 @@
import { describe, assert, it } from 'vitest';
import { flushSync } from '../../src/index-client';
import { flushSync, getAbortSignal } from '../../src/index-client';
import * as $ from '../../src/internal/client/runtime';
import { push, pop } from '../../src/internal/client/context';
import {
@ -1012,4 +1012,42 @@ describe('signals', () => {
destroy();
};
});
test('$effect can use getAbortSignal', () => {
return () => {
const n = state(0);
const abort_signals: AbortSignal[] = [];
const destroy = effect_root(() => {
render_effect(() => {
$.get(n);
const signal = getAbortSignal();
abort_signals.push(signal);
});
});
assert.deepEqual(
abort_signals.map((s) => s.aborted),
[false]
);
set(n, 1);
flushSync();
assert.deepEqual(
abort_signals.map((s) => s.aborted),
[true, false]
);
set(n, 2);
flushSync();
assert.deepEqual(
abort_signals.map((s) => s.aborted),
[true, true, false]
);
destroy();
};
});
});

@ -412,6 +412,7 @@ declare module 'svelte' {
* Synchronously flushes any pending state changes and those that result from it.
* */
export function flushSync(fn?: (() => void) | undefined): void;
export function getAbortSignal(): AbortSignal;
/**
* Create a snippet programmatically
* */

Loading…
Cancel
Save