From 6c6233f14010c6eaf0342ac515b16024d99abe89 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 12 Jul 2025 13:29:56 -0400 Subject: [PATCH] flesh out await_waterfall message --- .../.generated/client-warnings.md | 23 +++++++++++++++++-- .../messages/client-warnings/warnings.md | 23 +++++++++++++++++-- .../client/visitors/VariableDeclaration.js | 2 +- .../internal/client/reactivity/deriveds.js | 2 +- .../svelte/src/internal/client/warnings.js | 7 +++--- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/documentation/docs/98-reference/.generated/client-warnings.md b/documentation/docs/98-reference/.generated/client-warnings.md index 60cb02a1ee..1c75faef53 100644 --- a/documentation/docs/98-reference/.generated/client-warnings.md +++ b/documentation/docs/98-reference/.generated/client-warnings.md @@ -71,10 +71,29 @@ let total = $derived(await sum(a, b)); ### 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 derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app ``` -TODO +In a case like this... + +```js +let a = $derived(await one()); +let b = $derived(await two()); +``` + +...the second `$derived` will not be created until the first one has resolved. Since `await two()` does not depend on the value of `a`, this delay, often described as a 'waterfall', is unnecessary. + +(Note that if the values of `await one()` and `await two()` subsequently change, they can do so concurrently — the waterfall only occurs when the deriveds are first created.) + +You can solve this by creating the promises first and _then_ awaiting them: + +```js +let aPromise = $derived(one()); +let bPromise = $derived(two()); + +let a = $derived(await aPromise); +let b = $derived(await bPromise); +``` ### binding_property_non_reactive diff --git a/packages/svelte/messages/client-warnings/warnings.md b/packages/svelte/messages/client-warnings/warnings.md index e4390318eb..498c19a547 100644 --- a/packages/svelte/messages/client-warnings/warnings.md +++ b/packages/svelte/messages/client-warnings/warnings.md @@ -64,9 +64,28 @@ let total = $derived(await sum(a, b)); ## 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 derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app -TODO +In a case like this... + +```js +let a = $derived(await one()); +let b = $derived(await two()); +``` + +...the second `$derived` will not be created until the first one has resolved. Since `await two()` does not depend on the value of `a`, this delay, often described as a 'waterfall', is unnecessary. + +(Note that if the values of `await one()` and `await two()` subsequently change, they can do so concurrently — the waterfall only occurs when the deriveds are first created.) + +You can solve this by creating the promises first and _then_ awaiting them: + +```js +let aPromise = $derived(one()); +let bPromise = $derived(two()); + +let a = $derived(await aPromise); +let b = $derived(await bPromise); +``` ## binding_property_non_reactive diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index acf3bd6f44..19a7de5715 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -207,7 +207,7 @@ export function VariableDeclaration(node, context) { ); if (is_async) { - const location = dev && is_ignored(init, 'await_waterfall') && locate_node(init); + const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init); let call = b.call( '$.async_derived', b.thunk(expression, true), diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 0580918c9c..ecddcd671e 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -169,7 +169,7 @@ export function async_derived(fn, location) { setTimeout(() => { if (recent_async_deriveds.has(signal)) { - w.await_waterfall(location); + w.await_waterfall(/** @type {string} */ (signal.label), location); recent_async_deriveds.delete(signal); } }); diff --git a/packages/svelte/src/internal/client/warnings.js b/packages/svelte/src/internal/client/warnings.js index 902b471d8b..dfd50a8722 100644 --- a/packages/svelte/src/internal/client/warnings.js +++ b/packages/svelte/src/internal/client/warnings.js @@ -31,12 +31,13 @@ export function await_reactivity_loss(name) { } /** - * 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 derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app + * @param {string} name * @param {string} location */ -export function await_waterfall(location) { +export function await_waterfall(name, location) { 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 derived, \`${name}\` (${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 { console.warn(`https://svelte.dev/e/await_waterfall`); }