mirror of https://github.com/sveltejs/svelte
parent
a6221946cf
commit
7018c09247
@ -0,0 +1,63 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// A fork that is committed while it still waits for other async work (here: `<p>`) is a pending real batch:
|
||||||
|
// its {#await} promise is the real world's promise from then on, and as long as the batch is pending,
|
||||||
|
// the promise's states land along with the rest of the fork's state. Once the batch is done, they
|
||||||
|
// are their own batches again, like for any real update
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
instance.settle('p', 0);
|
||||||
|
await tick();
|
||||||
|
instance.settle('aw', 0);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>0</p><q>0</q>');
|
||||||
|
|
||||||
|
// resolves before the batch is done; the real world's older promise is obsolete once the fork is committed
|
||||||
|
instance.set({ a: 1 });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>0</p><i>pending</i>');
|
||||||
|
let f = fork(() => instance.set({ b: 10 }));
|
||||||
|
await tick();
|
||||||
|
f.commit();
|
||||||
|
await tick();
|
||||||
|
instance.settle('aw', 11);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>0</p><i>pending</i>');
|
||||||
|
instance.settle('aw', 1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>0</p><i>pending</i>');
|
||||||
|
instance.settle('p', 10);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>10</p><q>11</q>');
|
||||||
|
|
||||||
|
// resolves after the batch is done
|
||||||
|
f = fork(() => instance.set({ b: 20 }));
|
||||||
|
await tick();
|
||||||
|
f.commit();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>10</p><q>11</q>');
|
||||||
|
instance.settle('p', 20);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>20</p><i>pending</i>');
|
||||||
|
instance.settle('aw', 21);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>20</p><q>21</q>');
|
||||||
|
|
||||||
|
// a real update after the commit supersedes the fork's promise
|
||||||
|
f = fork(() => instance.set({ b: 30 }));
|
||||||
|
await tick();
|
||||||
|
f.commit();
|
||||||
|
await tick();
|
||||||
|
instance.set({ a: 2 });
|
||||||
|
await tick();
|
||||||
|
instance.settle('aw', 31);
|
||||||
|
await tick();
|
||||||
|
instance.settle('aw', 32);
|
||||||
|
await tick();
|
||||||
|
instance.settle('p', 30);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>30</p><q>32</q>');
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
<script>
|
||||||
|
let a = $state(0);
|
||||||
|
let b = $state(0);
|
||||||
|
|
||||||
|
/** @type {Map<string, Array<() => void>>} */
|
||||||
|
const registry = new Map();
|
||||||
|
|
||||||
|
function f(tag, value) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const key = tag + value;
|
||||||
|
if (!registry.has(key)) registry.set(key, []);
|
||||||
|
registry.get(key).push(() => resolve(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set(values) {
|
||||||
|
if ('a' in values) a = values.a;
|
||||||
|
if ('b' in values) b = values.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resolve the promises created for `tag` and `value` */
|
||||||
|
export function settle(tag, value) {
|
||||||
|
for (const r of registry.get(tag + value) ?? []) r();
|
||||||
|
registry.delete(tag + value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{await f('p', b)}</p>
|
||||||
|
{#await f('aw', a + b)}<i>pending</i>{:then v}<q>{v}</q>{/await}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// Resolving a fork's {#await} promise must not interfere with real work happening at the same time
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
instance.settle('a', 0);
|
||||||
|
instance.settle('b', 0);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q><s>0|0</s>');
|
||||||
|
|
||||||
|
// the real update's pending state is queued while the fork's promise resolves:
|
||||||
|
// it must not end up in the fork
|
||||||
|
let f = fork(() => instance.set({ b: 1 }));
|
||||||
|
await tick();
|
||||||
|
instance.set({ a: 1 });
|
||||||
|
instance.settle('b', 1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i><s>0|1</s>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i><s>0|1</s>');
|
||||||
|
instance.settle('a', 1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>1</q><s>0|1</s>');
|
||||||
|
|
||||||
|
// a real update right after the fork's promise resolved (in the fork) must still show
|
||||||
|
f = fork(() => instance.set({ b: 2 }));
|
||||||
|
await tick();
|
||||||
|
instance.latest('b').then(() => instance.set({ a: 5 }));
|
||||||
|
instance.settle('b', 2);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i><s>0|5</s>');
|
||||||
|
f.discard();
|
||||||
|
instance.settle('a', 5);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>5</q><s>0|5</s>');
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<script>
|
||||||
|
let a = $state(0);
|
||||||
|
let b = $state(0);
|
||||||
|
|
||||||
|
/** @type {Map<string, Array<() => void>>} */
|
||||||
|
const registry = new Map();
|
||||||
|
/** @type {Map<string, Promise<number>>} */
|
||||||
|
const promises = new Map();
|
||||||
|
|
||||||
|
function f(tag, value) {
|
||||||
|
const promise = new Promise((resolve) => {
|
||||||
|
const key = tag + value;
|
||||||
|
if (!registry.has(key)) registry.set(key, []);
|
||||||
|
registry.get(key).push(() => resolve(value));
|
||||||
|
});
|
||||||
|
promises.set(tag, promise);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set(values) {
|
||||||
|
if ('a' in values) a = values.a;
|
||||||
|
if ('b' in values) b = values.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resolve the promises created for `tag` and `value` */
|
||||||
|
export function settle(tag, value) {
|
||||||
|
for (const r of registry.get(tag + value) ?? []) r();
|
||||||
|
registry.delete(tag + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** the latest promise created for `tag` */
|
||||||
|
export function latest(tag) {
|
||||||
|
return promises.get(tag);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await f('a', a)}<i>pending</i>{:then v}<q>{v}</q>{/await}
|
||||||
|
{#await f('b', b)}<i>pending</i>{:then v}<s>{v}|{a}</s>{/await}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// The pending state of a fork's {#await} promise, and its result, must not show in the real world unless
|
||||||
|
// the fork is committed. Real updates must keep working while a fork is alive, and a promise of the real
|
||||||
|
// world must still resolve in the real world when a fork re-runs the block
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(0);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
// pending and resolved in the fork, then discarded
|
||||||
|
let f = fork(() => instance.set({ b: 1 }));
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
instance.settle(1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
// rejected in the fork, then discarded
|
||||||
|
f = fork(() => instance.set({ b: -1 }));
|
||||||
|
instance.settle(-1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
// For comparison, a real update: pending, then resolved
|
||||||
|
instance.set({ b: 2 });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(2);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>2</q>');
|
||||||
|
|
||||||
|
// committed while pending: shows the pending state, just like a real update would
|
||||||
|
f = fork(() => instance.set({ b: 3 }));
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>2</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(3);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>3</q>');
|
||||||
|
|
||||||
|
// a real update while the fork is pending (a + b: real 4 + 3, fork 4 + 10)
|
||||||
|
f = fork(() => instance.set({ b: 10 }));
|
||||||
|
await tick();
|
||||||
|
instance.set({ a: 4 });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(14);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(7);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>7</q>');
|
||||||
|
instance.settle(10); // the fork's obsolete promise (from before it saw a = 4)
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>7</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>14</q>');
|
||||||
|
|
||||||
|
// a real update while the fork is pending, then discarded (real 5 + 10, fork 5 + 20)
|
||||||
|
f = fork(() => instance.set({ b: 20 }));
|
||||||
|
await tick();
|
||||||
|
instance.set({ a: 5 });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(15);
|
||||||
|
instance.settle(25);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>15</q>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>15</q>');
|
||||||
|
instance.settle(24);
|
||||||
|
|
||||||
|
// a real promise that is still pending when a fork re-runs the block must resolve in the real world
|
||||||
|
instance.set({ a: 6 });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
f = fork(() => instance.set({ b: 30 }));
|
||||||
|
await tick();
|
||||||
|
instance.settle(16);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>16</q>');
|
||||||
|
f.discard();
|
||||||
|
instance.settle(36);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>16</q>');
|
||||||
|
|
||||||
|
// ...also when the fork's promise resolves first, and the fork is committed afterwards
|
||||||
|
instance.set({ a: 7 });
|
||||||
|
await tick();
|
||||||
|
f = fork(() => instance.set({ b: 40 }));
|
||||||
|
instance.settle(47);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(17);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>17</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>47</q>');
|
||||||
|
|
||||||
|
// ...but once the fork is committed, the real world's older promise is obsolete
|
||||||
|
instance.set({ a: 8 });
|
||||||
|
await tick();
|
||||||
|
f = fork(() => instance.set({ b: 50 }));
|
||||||
|
await tick();
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(48);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
instance.settle(58);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>58</q>');
|
||||||
|
|
||||||
|
// rejected in the fork, then committed
|
||||||
|
f = fork(() => instance.set({ b: -60 }));
|
||||||
|
instance.settle(-52);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>58</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<s>-52</s>');
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
<script>
|
||||||
|
let a = $state(0);
|
||||||
|
let b = $state(0);
|
||||||
|
|
||||||
|
/** @type {Map<number, Array<() => void>>} */
|
||||||
|
const registry = new Map();
|
||||||
|
|
||||||
|
function f(value) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!registry.has(value)) registry.set(value, []);
|
||||||
|
registry.get(value).push(() => (value < 0 ? reject(value) : resolve(value)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set(values) {
|
||||||
|
if ('a' in values) a = values.a;
|
||||||
|
if ('b' in values) b = values.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resolve the promises created for `value` */
|
||||||
|
export function settle(value) {
|
||||||
|
for (const r of registry.get(value) ?? []) r();
|
||||||
|
registry.delete(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await f(a + b)}<i>pending</i>{:then v}<q>{v}</q>{:catch e}<s>{e}</s>{/await}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// A fork re-running an {#await} block must not make the real world's pending promise obsolete
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i>');
|
||||||
|
|
||||||
|
const f = fork(() => instance.set_b(1));
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
instance.settle(0);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
f.discard();
|
||||||
|
instance.settle(1);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<script>
|
||||||
|
let b = $state(0);
|
||||||
|
|
||||||
|
/** @type {Map<number, Array<() => void>>} */
|
||||||
|
const registry = new Map();
|
||||||
|
|
||||||
|
function f(value) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (!registry.has(value)) registry.set(value, []);
|
||||||
|
registry.get(value).push(() => resolve(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set_b(v) {
|
||||||
|
b = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** resolve the promises created for `value` */
|
||||||
|
export function settle(value) {
|
||||||
|
for (const r of registry.get(value) ?? []) r();
|
||||||
|
registry.delete(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await f(b)}<i>pending</i>{:then v}<q>{v}</q>{/await}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// An {#await} block without dependencies can't re-run, so it is the same in every batch: if it's
|
||||||
|
// created in a fork, a real batch that adopts the fork's branch must see its states as well
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
const f = fork(() => instance.set({ show: true, x: 1 }));
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>0</p>');
|
||||||
|
|
||||||
|
instance.set({ show: true });
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<i>pending</i><p>0</p>');
|
||||||
|
|
||||||
|
instance.settle(5);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>5</q><p>0</p>');
|
||||||
|
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>5</q><p>0</p>');
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<script>
|
||||||
|
let show = $state(false);
|
||||||
|
let x = $state(0);
|
||||||
|
|
||||||
|
/** @type {(value: number) => void} */
|
||||||
|
let resolve;
|
||||||
|
const promise = new Promise((r) => (resolve = r));
|
||||||
|
|
||||||
|
export function set(values) {
|
||||||
|
if ('show' in values) show = values.show;
|
||||||
|
if ('x' in values) x = values.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function settle(value) {
|
||||||
|
resolve(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if show}{#await promise}<i>pending</i>{:then v}<q>{v}</q>{/await}{/if}<p>{x}</p>
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
import { fork, tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// A fork's {#await} results (then and catch) must not end up in the real world
|
||||||
|
// unless the fork is committed
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, instance }) {
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
// resolved, then discarded
|
||||||
|
let f = fork(() => instance.set_b(2));
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
assert.equal(instance.pending(), 0); // no refetch in the real world
|
||||||
|
|
||||||
|
// rejected, then discarded
|
||||||
|
f = fork(() => instance.set_b(-1));
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
f.discard();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
|
||||||
|
// resolved, then committed
|
||||||
|
f = fork(() => instance.set_b(3));
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>0</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>3</q>');
|
||||||
|
assert.equal(instance.pending(), 0);
|
||||||
|
|
||||||
|
// rejected, then committed
|
||||||
|
f = fork(() => instance.set_b(-2));
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>3</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<s>-2</s>');
|
||||||
|
|
||||||
|
// For comparison, a real update: without a pending snippet, the previous
|
||||||
|
// content is removed (a microtask later), and the result shows once it resolves
|
||||||
|
instance.set_b(4);
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '');
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>4</q>');
|
||||||
|
|
||||||
|
// committed while pending (after the pending state was reached in the fork):
|
||||||
|
// the real world is in the same state as after a real update
|
||||||
|
f = fork(() => instance.set_b(5));
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>4</q>');
|
||||||
|
await f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '');
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>5</q>');
|
||||||
|
assert.equal(instance.pending(), 0);
|
||||||
|
|
||||||
|
// committed synchronously (`fork` flushes synchronously, which reaches the pending state)
|
||||||
|
f = fork(() => instance.set_b(6));
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>5</q>');
|
||||||
|
f.commit();
|
||||||
|
assert.htmlEqual(target.innerHTML, '');
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>6</q>');
|
||||||
|
assert.equal(instance.pending(), 0);
|
||||||
|
|
||||||
|
// discarded while pending, resolved afterwards
|
||||||
|
f = fork(() => instance.set_b(7));
|
||||||
|
await tick();
|
||||||
|
f.discard();
|
||||||
|
instance.resolve_all();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, '<q>6</q>');
|
||||||
|
assert.equal(instance.pending(), 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
<script>
|
||||||
|
let b = $state(0);
|
||||||
|
const registry = [];
|
||||||
|
|
||||||
|
function f(value) {
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
registry.push(() => (value < 0 ? reject(value) : resolve(value)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set_b(v) {
|
||||||
|
b = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolve_all() {
|
||||||
|
for (const r of registry.splice(0)) r();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pending() {
|
||||||
|
return registry.length;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await f(b) then v}<q>{v}</q>{:catch e}<s>{e}</s>{/await}
|
||||||
Loading…
Reference in new issue