flesh out await_reactivity_loss warning

pull/15844/head
Rich Harris 3 months ago
parent c0283713e6
commit 7a08d9bee5

@ -37,15 +37,41 @@ function add() {
### await_reactivity_loss ### await_reactivity_loss
``` ```
Detected reactivity loss Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await`
``` ```
TODO Svelte's signal-based reactivity works by tracking which bits of state are read when a template or `$derived(...)` expression executes. If an expression contains an `await`, Svelte transforms it such that any state _after_ the `await` is also tracked — in other words, in a case like this...
```js
let total = $derived(await a + b);
```
...both `a` and `b` are tracked, even though `b` is only read once `a` has resolved, after the initial execution.
This does _not_ apply to an `await` that is not 'visible' inside the expression. In a case like this...
```js
async function sum() {
return await a + b;
}
let total = $derived(await sum());
```
...`total` will depend on `a` (which is read immediately) but not `b` (which is not). The solution is to pass the values into the function:
```js
async function sum(a, b) {
return await a + b;
}
let total = $derived(await sum(a, b));
```
### await_waterfall ### await_waterfall
``` ```
An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app. An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app
``` ```
TODO TODO

@ -32,13 +32,39 @@ function add() {
## await_reactivity_loss ## await_reactivity_loss
> Detected reactivity loss > Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await`
TODO Svelte's signal-based reactivity works by tracking which bits of state are read when a template or `$derived(...)` expression executes. If an expression contains an `await`, Svelte transforms it such that any state _after_ the `await` is also tracked — in other words, in a case like this...
```js
let total = $derived(await a + b);
```
...both `a` and `b` are tracked, even though `b` is only read once `a` has resolved, after the initial execution.
This does _not_ apply to an `await` that is not 'visible' inside the expression. In a case like this...
```js
async function sum() {
return await a + b;
}
let total = $derived(await sum());
```
...`total` will depend on `a` (which is read immediately) but not `b` (which is not). The solution is to pass the values into the function:
```js
async function sum(a, b) {
return await a + b;
}
let total = $derived(await sum(a, b));
```
## await_waterfall ## await_waterfall
> An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app. > An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app
TODO TODO

@ -875,7 +875,10 @@ export function get(signal) {
var was_read = from_async_derived.deps !== null && from_async_derived.deps.includes(signal); var was_read = from_async_derived.deps !== null && from_async_derived.deps.includes(signal);
if (!tracking && !was_read) { if (!tracking && !was_read) {
w.await_reactivity_loss(); w.await_reactivity_loss(/** @type {string} */ (signal.label));
// eslint-disable-next-line no-console
console.warn(get_stack('TracedAt'));
} }
} }

@ -19,23 +19,24 @@ export function assignment_value_stale(property, location) {
} }
/** /**
* Detected reactivity loss * Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await`
* @param {string} name
*/ */
export function await_reactivity_loss() { export function await_reactivity_loss(name) {
if (DEV) { if (DEV) {
console.warn(`%c[svelte] await_reactivity_loss\n%cDetected reactivity loss\nhttps://svelte.dev/e/await_reactivity_loss`, bold, normal); console.warn(`%c[svelte] await_reactivity_loss\n%cDetected reactivity loss when reading \`${name}\`. This happens when state is read in an async function after an earlier \`await\`\nhttps://svelte.dev/e/await_reactivity_loss`, bold, normal);
} else { } else {
console.warn(`https://svelte.dev/e/await_reactivity_loss`); console.warn(`https://svelte.dev/e/await_reactivity_loss`);
} }
} }
/** /**
* An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app. * An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app
* @param {string} location * @param {string} location
*/ */
export function await_waterfall(location) { export function await_waterfall(location) {
if (DEV) { if (DEV) {
console.warn(`%c[svelte] await_waterfall\n%cAn async value (${location}) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app.\nhttps://svelte.dev/e/await_waterfall`, bold, normal); console.warn(`%c[svelte] await_waterfall\n%cAn async value (${location}) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app\nhttps://svelte.dev/e/await_waterfall`, bold, normal);
} else { } else {
console.warn(`https://svelte.dev/e/await_waterfall`); console.warn(`https://svelte.dev/e/await_waterfall`);
} }

Loading…
Cancel
Save