Stores not honoring contract described in the documentation
Describe the bug
In https://svelte.dev/docs/svelte/stores#Store-contract the documentations states:
A store may optionally contain a .set method, which [...] synchronously calls all of the store’s active subscription functions.
This is not the behavior I observe from Svelte's built-in stores, as they seem to schedule the calls to the subscriptions till after the calling function is done. I understand that this behavior is probably intended, my main concern is with the documentation.
It would be very helpful to have a proper documentation of how Svelte's stores actually behave.
Reproduction
Consider the following example:
<script lang="ts">
import { readonly, type Writable, writable } from 'svelte/store'
let name = 'world';
const select: Writable<number> = writable(0)
const select2: Writable<number> = writable($select)
let i = 0
$: console.log("select ", $select)
$: console.log("select2 ", $select2)
select.subscribe((v) => {
console.log('select subscribe ', v)
select2.set(v)
console.log('after set')
})
select2.subscribe((v) => {
console.log('select 2 subscribe ', v)
select.set(v)
})
</script>
<button on:click={() => select.set(++i)}>assign</button>
Which (after clicking the button) results in the output:
select subscribe 1
after set
select 2 subscribe 1
select 1
select2 1
As you can see, the .set method finishes and the surrounding code is executed before the subscriptions are called.
Logs
System Info
System:
OS: Windows 11 10.0.22621
CPU: (16) x64 AMD Ryzen 7 PRO 4750U with Radeon Graphics
Memory: 12.33 GB / 31.37 GB
Binaries:
Node: 22.14.0 - C:\Program Files\nodejs\node.EXE
npm: 10.9.2 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (127.0.2651.74)
Internet Explorer: 11.0.22621.3527
Severity
annoyance
You might be confusing synchronously with immediately or instantly. I think what you're seeing is Svelte waiting for the current subscribe to finish before triggering the next subscribers.
Edit: synchronous means that this will always work:
<script>
import { writable } from 'svelte/store'
let store = writable('foo');
let value;
const unsub = store.subscribe(v => {
value = v;
});
store.set('bar');
unsub();
console.log(value);
</script>
https://svelte.dev/playground/hello-world?version=5.32.1#H4sIAAAAAAAAA22PzW6EMAyEX8XKJUGq2Dv7I_XWd1h6SBZTRTIJSgx0hXj3TQKteujNHn8zI6_C6QFFIz6QyMPiA3WgsLOMXSXeRG8Jo2juq-DnmLksJP1wvY9jHWckzprREf_TH94xOk4x4hIfwY58a13Ldhh9YFhhCZa1IYQN-uAHkLvzFNkHlAlNMCFD2eH6yyvZey-r88991jTheedTZ2SYXJxMchRnneZcb1DNcL3BmrmWiysxc8nZ9rjDgKyk0eHoKGmq-tPgCWvyX6pk5MPldDyY3mb8ZtFwmHD7TJu2tFjXiabXFHF7AUdEhs95AQAA
Edit2: I think this makes it absolutely clear what synchronous means:
<button on:click={() => {
select.set(++i);
console.log('after set');
}}>assign</button>
My issue is not the word "synchronously". Just ignore the word:
A store may optionally contain a .set method, which [...] calls all of the store’s active subscription functions.
For me what it means when a method calls a function is that the call is inside that method. Otherwise it should be something like "which ensures that the subscribe functions are called (synchronously) in the future".
I showed this sentence to several colleagues and everyone understood it that way.
Please do me a favor and honestly ask yourself, if you had no idea how svelte works, would you expect the first method to finish before calling the second one after reading that sentence from the documentation?
In a case like your one, you expect the execution order of subscribers be
- store1subscriber1
- store1subscriber2
- store2subscriber1
- store2subscriber2
- store2subscriber3
- store1subscriber3
- store1subscriber4
but it is
- store1subscriber1
- store1subscriber2
- store1subscriber3
- store1subscriber4
- store2subscriber1
- store2subscriber2
- store2subscriber3
It was introduced in #3219 for a reason.
You can always open a PR to the docs. There is even a button for this in the docs.
Ok, look, I'm not a front end developer and I don't regularly use Svelte. I just had to fix something for a random task, came to your docs for information and found something that was (in my view) wrong or at least misleading, so I thought I'd tell you. Do with that what you want, feel free to close this issue.
I'm not going to fix your docs because I'm neither qualified nor willing to do so, especially since none of you seem to care about the state of your documentation anyways.