fix: ignore fork `discard()` after `commit()` (#17034)

* fix: ignore fork `discard()` after `commit()`

* fix message
pull/17035/head
Rich Harris 2 days ago committed by GitHub
parent 875a04170e
commit 657ec89caa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ignore fork `discard()` after `commit()`

@ -149,7 +149,7 @@ This restriction only applies when using the `experimental.async` option, which
### fork_discarded ### fork_discarded
``` ```
Cannot commit a fork that was already committed or discarded Cannot commit a fork that was already discarded
``` ```
### fork_timing ### fork_timing

@ -114,7 +114,7 @@ This restriction only applies when using the `experimental.async` option, which
## fork_discarded ## fork_discarded
> Cannot commit a fork that was already committed or discarded > Cannot commit a fork that was already discarded
## fork_timing ## fork_timing

@ -262,12 +262,12 @@ export function flush_sync_in_effect() {
} }
/** /**
* Cannot commit a fork that was already committed or discarded * Cannot commit a fork that was already discarded
* @returns {never} * @returns {never}
*/ */
export function fork_discarded() { export function fork_discarded() {
if (DEV) { if (DEV) {
const error = new Error(`fork_discarded\nCannot commit a fork that was already committed or discarded\nhttps://svelte.dev/e/fork_discarded`); const error = new Error(`fork_discarded\nCannot commit a fork that was already discarded\nhttps://svelte.dev/e/fork_discarded`);
error.name = 'Svelte error'; error.name = 'Svelte error';

@ -913,28 +913,36 @@ export function fork(fn) {
e.fork_timing(); e.fork_timing();
} }
const batch = Batch.ensure(); var batch = Batch.ensure();
batch.is_fork = true; batch.is_fork = true;
const settled = batch.settled(); var committed = false;
var settled = batch.settled();
flushSync(fn); flushSync(fn);
// revert state changes // revert state changes
for (const [source, value] of batch.previous) { for (var [source, value] of batch.previous) {
source.v = value; source.v = value;
} }
return { return {
commit: async () => { commit: async () => {
if (committed) {
await settled;
return;
}
if (!batches.has(batch)) { if (!batches.has(batch)) {
e.fork_discarded(); e.fork_discarded();
} }
committed = true;
batch.is_fork = false; batch.is_fork = false;
// apply changes // apply changes
for (const [source, value] of batch.current) { for (var [source, value] of batch.current) {
source.v = value; source.v = value;
} }
@ -945,9 +953,9 @@ export function fork(fn) {
// TODO maybe there's a better implementation? // TODO maybe there's a better implementation?
flushSync(() => { flushSync(() => {
/** @type {Set<Effect>} */ /** @type {Set<Effect>} */
const eager_effects = new Set(); var eager_effects = new Set();
for (const source of batch.current.keys()) { for (var source of batch.current.keys()) {
mark_eager_effects(source, eager_effects); mark_eager_effects(source, eager_effects);
} }
@ -959,7 +967,7 @@ export function fork(fn) {
await settled; await settled;
}, },
discard: () => { discard: () => {
if (batches.has(batch)) { if (!committed && batches.has(batch)) {
batches.delete(batch); batches.delete(batch);
batch.discard(); batch.discard();
} }

Loading…
Cancel
Save