From c92620dcbe25f741c55aca0c19d8a94b5b9dfe15 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 16 Jul 2024 08:18:59 -0700 Subject: [PATCH] feat: skip pending block for already-resolved promises (#12274) * feat: skip pending block for already-resolved promises * update tests * update docs --- .changeset/chatty-ghosts-unite.md | 5 +++++ .../src/internal/client/dom/blocks/await.js | 2 +- .../expected.html | 6 +++--- .../input.svelte | 11 ++++------ .../_config.js | 12 +++++------ .../expected.css | 6 +++--- .../expected.html | 4 ++-- .../input.svelte | 13 ++++++------ .../expected.html | 6 +++--- .../input.svelte | 13 +++++------- .../siblings-combinator-await/_config.js | 16 +++++++------- .../siblings-combinator-await/expected.css | 8 +++---- .../siblings-combinator-await/expected.html | 4 ++-- .../siblings-combinator-await/input.svelte | 15 ++++++------- .../await-block-func-function/_config.js | 4 ---- .../await-catch-no-expression/_config.js | 6 +----- .../await-conservative-update/_config.js | 4 ---- .../samples/await-containing-if/_config.js | 4 ---- .../samples/await-in-each/_config.js | 4 ---- .../_config.js | 1 - .../_config.js | 3 +-- .../samples/await-set-simultaneous/_config.js | 1 + .../await-then-blowback-reactive/_config.js | 2 -- .../await-then-catch-anchor/_config.js | 7 ++----- .../samples/await-then-catch-event/_config.js | 4 ---- .../samples/await-then-catch-if/_config.js | 4 ---- .../await-then-catch-in-slot/_config.js | 5 +---- .../await-then-catch-multiple/_config.js | 8 ++----- .../await-then-catch-no-values/_config.js | 5 ++--- .../samples/await-then-catch-order/_config.js | 4 ---- .../await-then-catch-static/_config.js | 7 ++----- .../samples/await-then-catch/_config.js | 7 ++----- .../_config.js | 4 ---- .../await-then-destruct-array/_config.js | 4 ---- .../_config.js | 4 ---- .../await-then-destruct-object/_config.js | 4 ---- .../samples/await-then-if/_config.js | 4 ---- .../await-then-no-expression/_config.js | 7 +------ .../samples/await-then-shorthand/_config.js | 3 ++- .../samples/await-with-components/_config.js | 3 +++ .../samples/await-with-update-2/_config.js | 4 ---- .../samples/await-with-update/_config.js | 4 ---- .../samples/await-without-catch/_config.js | 7 ++----- .../samples/context-in-await/_config.js | 4 ---- .../_config.js | 1 + .../transition-js-await-block/_config.js | 3 ++- .../samples/await-resolve-2/_config.js | 7 +++++-- .../samples/await-resolve/_config.js | 9 ++++++-- .../03-appendix/02-breaking-changes.md | 21 +++++++++++++++++++ 49 files changed, 116 insertions(+), 178 deletions(-) create mode 100644 .changeset/chatty-ghosts-unite.md diff --git a/.changeset/chatty-ghosts-unite.md b/.changeset/chatty-ghosts-unite.md new file mode 100644 index 0000000000..076616d2da --- /dev/null +++ b/.changeset/chatty-ghosts-unite.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: skip pending block for already-resolved promises diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index 5477176660..49a7bd5892 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -139,7 +139,7 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { } else { // Wait a microtask before checking if we should show the pending state as // the promise might have resolved by the next microtask. - queue_micro_task(() => { + Promise.resolve().then(() => { if (!resolved) update(PENDING, true); }); } diff --git a/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html b/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html index de97b02a5e..884480bca1 100644 --- a/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html +++ b/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/expected.html @@ -1,4 +1,4 @@
-
-
-
\ No newline at end of file +
+
+
diff --git a/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte b/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte index a3e4230161..5fb2c1e540 100644 --- a/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte +++ b/packages/svelte/tests/css/samples/general-siblings-combinator-await-not-exhaustive/input.svelte @@ -1,7 +1,3 @@ - -
-{#await promise} + +{#await true}
{:then value}
diff --git a/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/expected.html b/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/expected.html index de97b02a5e..884480bca1 100644 --- a/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/expected.html +++ b/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/expected.html @@ -1,4 +1,4 @@
-
-
-
\ No newline at end of file +
+
+
diff --git a/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/input.svelte b/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/input.svelte index 520c6f39a9..30d48d1a6a 100644 --- a/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/input.svelte +++ b/packages/svelte/tests/css/samples/siblings-combinator-await-not-exhaustive/input.svelte @@ -1,7 +1,3 @@ - -
-{#await promise} + +{#await true}
{:then value}
diff --git a/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js index 3125eafb53..3b64e74f24 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js @@ -7,10 +7,6 @@ export default test({ }; }, - html: ` - Waiting... - `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve({ func: 12345 })); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js index a13e636f3c..7ef3df596b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js @@ -13,11 +13,6 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -
-

the promise is pending

- `, - async test({ assert, component, target }) { deferred.resolve(42); @@ -27,6 +22,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

the promise is pending

'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js index c36d75ea1f..c7839f689f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js @@ -2,10 +2,6 @@ import { test } from '../../test'; import { sleep } from './sleep.js'; export default test({ - html: ` -

loading...

- `, - test({ assert, target }) { return sleep(50).then(() => { assert.htmlEqual( diff --git a/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js index 3c9bab013f..e46ef352f3 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js @@ -13,10 +13,6 @@ export default test({ return { thePromise: deferred.promise, show: true }; }, - html: ` -

loading...

- `, - test({ assert, component, target }) { deferred.resolve(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js index 71831276a6..ea2ded02e3 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js @@ -19,10 +19,6 @@ export default test({ return { items }; }, - html: ` -

a title: loading...

- `, - test({ assert, target }) { fulfil(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js index e207ef31d6..653378f52b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js @@ -1,7 +1,6 @@ import { test } from '../../test'; export default test({ - html: 'Loading...', async test({ assert, component, target }) { await component.test(); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js index 1d775465cd..5770a65a9c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js @@ -1,9 +1,8 @@ import { test } from '../../test'; export default test({ - html: '

wait for it...

', test({ assert, component, target }) { - return component.promise.then(async () => { + return component.promise.then(() => { assert.htmlEqual( target.innerHTML, ` diff --git a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js index 9fe8683973..d1b93da8eb 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js @@ -7,6 +7,7 @@ export default test({ }); component.promise = promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

wait for it...

'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js index 665b8d94b6..8d45e3a42f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js @@ -3,8 +3,6 @@ import { ok, test } from '../../test'; export default test({ async test({ assert, component, target }) { - assert.htmlEqual(target.innerHTML, 'Loading...'); - await component.promise; await Promise.resolve(); const span = target.querySelector('span'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js index d778d2c8d2..36b1e836fe 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js @@ -13,15 +13,11 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -

loading...

- `, - test({ assert, component, target }) { deferred.resolve(42); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual( target.innerHTML, ` @@ -32,6 +28,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

loading...

'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js index 26d22b8c1a..598e657f06 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js @@ -15,10 +15,6 @@ export default test({ }; }, - html: ` -

loading...

- `, - test({ assert, component, target, window }) { deferred.resolve(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js index d68f1597fc..104ff82ea8 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js @@ -12,10 +12,6 @@ export default test({ return { show: true, thePromise }; }, - html: ` -

loading...

- `, - test({ assert, component, target }) { fulfil(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js index 09ab6e3912..6d6cfa4a28 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js @@ -13,10 +13,6 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -

loading...

- `, - async test({ assert, component, target }) { deferred.resolve(42); @@ -25,6 +21,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

loading...

'); deferred.reject(new Error('something broke')); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js index 719484ff0e..ff90451519 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js @@ -13,16 +13,11 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -

loading...

-

loading...

- `, - test({ assert, component, target }) { deferred.resolve(42); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual( target.innerHTML, ` @@ -34,6 +29,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js index 4608be3edd..aad71a1df0 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js @@ -13,18 +13,17 @@ export default test({ return { thePromise: deferred.promise }; }, - html: 'waiting', - test({ assert, component, target }) { deferred.resolve(9000); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual(target.innerHTML, 'resolved'); deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, 'waiting'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js index e4ef68a75e..b12d5bc989 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js @@ -12,10 +12,6 @@ export default test({ return { thePromise }; }, - html: ` -

loading...

true!

- `, - test({ assert, target }) { fulfil(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js index 46608c41e8..1e8ae8cad2 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js @@ -12,15 +12,11 @@ export default test({ return { promise }; }, - html: ` -

loading...

- `, - test({ assert, component, target }) { fulfil(42); return promise - .then(() => { + .then(async () => { assert.htmlEqual( target.innerHTML, ` @@ -33,6 +29,7 @@ export default test({ }); component.promise = promise; + await Promise.resolve(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js index 33a8eb2bab..7ad918a174 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js @@ -13,15 +13,11 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -

loading...

- `, - test({ assert, component, target }) { deferred.resolve(42); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual( target.innerHTML, ` @@ -32,6 +28,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

loading...

'); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js index ee8b8e4a0e..e914fba478 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js @@ -7,10 +7,6 @@ export default test({ }; }, - html: ` - loading... - `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve([1, 2, 3, 4, 5, 6, 7, 8])); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js index 1d830ce582..9ab61331ef 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js @@ -7,10 +7,6 @@ export default test({ }; }, - html: ` - loading... - `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve([1, 2])); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js index a5d1e2195e..35c72e35b9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js @@ -7,10 +7,6 @@ export default test({ }; }, - html: ` - loading... - `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve([10, 11, 12, 13, 14, 15])); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js index 5c7989c933..d098da8370 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js @@ -7,10 +7,6 @@ export default test({ }; }, - html: ` - loading... - `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve({ error: 'error message' })); assert.htmlEqual( diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js index 27b111d68b..348075c4c5 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js @@ -12,10 +12,6 @@ export default test({ return { thePromise }; }, - html: ` - loading... - `, - async test({ assert, target }) { fulfil([]); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js index 7790a06d4d..a7b8bac126 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js @@ -13,12 +13,6 @@ export default test({ return { thePromise: deferred.promise }; }, - html: ` -
-
-

the promise is pending

- `, - expect_unhandled_rejections: true, async test({ assert, component, target }) { deferred.resolve(); @@ -39,6 +33,7 @@ export default test({ const local = (deferred = create_deferred()); component.thePromise = local.promise; + await Promise.resolve(); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js index 79e7094c6c..4c71961420 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js @@ -19,7 +19,7 @@ export default test({ deferred.resolve(42); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual( target.innerHTML, ` @@ -30,6 +30,7 @@ export default test({ deferred = create_deferred(); component.thePromise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, ''); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js index 3798e8dc08..7198203756 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js @@ -11,6 +11,7 @@ export default test({ let promise = new Promise((ok) => (resolve = ok)); component.promise = promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, 'Loading...'); resolve(42); @@ -19,6 +20,7 @@ export default test({ promise = new Promise((ok, fail) => (reject = fail)); component.promise = promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, 'Loading...'); reject(99); @@ -27,6 +29,7 @@ export default test({ promise = new Promise((ok) => (resolve = ok)); component.promise = promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, 'Loading...'); resolve(1); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js index c091d4fbc8..93d28ebefa 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js @@ -8,10 +8,6 @@ export default test({ }; }, - html: ` -

loading...

- `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve({ value: 'success', diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js index cea4955911..7f5aa010b4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js @@ -8,10 +8,6 @@ export default test({ }; }, - html: ` -

loading...

- `, - async test({ assert, component, target }) { await (component.thePromise = Promise.resolve(component.Component)); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js index a4db703dc4..e7fcc52efb 100644 --- a/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js @@ -13,21 +13,18 @@ export default test({ return { promise: deferred.promise }; }, - html: ` -

loading...

- `, - expect_unhandled_rejections: true, test({ assert, component, target }) { deferred.resolve(42); return deferred.promise - .then(() => { + .then(async () => { assert.htmlEqual(target.innerHTML, '

loaded

'); deferred = create_deferred(); component.promise = deferred.promise; + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

loading...

'); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js index 1d131be782..b9e76c33e9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js @@ -1,10 +1,6 @@ import { test } from '../../test'; export default test({ - html: ` -

...waiting

- `, - async test({ assert, component, target }) { await component.promise; diff --git a/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block-outros/_config.js b/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block-outros/_config.js index 1ce8a85028..b4c108afb4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block-outros/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block-outros/_config.js @@ -14,6 +14,7 @@ export default test({ intro: true, async test({ assert, target, component, raf }) { + await Promise.resolve(); assert.htmlEqual(target.innerHTML, '

loading...

'); let time = 0; diff --git a/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block/_config.js index 706b306ebb..171ed5c82d 100644 --- a/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/transition-js-await-block/_config.js @@ -16,7 +16,8 @@ export default test({ intro: true, - test({ assert, target, raf }) { + async test({ assert, target, raf }) { + await Promise.resolve(); const p = /** @type {HTMLParagraphElement & { foo: number }} */ (target.querySelector('p')); raf.tick(0); diff --git a/packages/svelte/tests/runtime-runes/samples/await-resolve-2/_config.js b/packages/svelte/tests/runtime-runes/samples/await-resolve-2/_config.js index 88f1b1e961..b72a0f100f 100644 --- a/packages/svelte/tests/runtime-runes/samples/await-resolve-2/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/await-resolve-2/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - async test({ assert, target, logs }) { + async test({ assert, target, logs, variant }) { const [b1, b2, b3, b4] = target.querySelectorAll('button'); b1.click(); await Promise.resolve(); @@ -16,6 +16,9 @@ export default test({ b4.click(); await Promise.resolve(); await Promise.resolve(); - assert.deepEqual(logs, ['pending', 'a', 'b', 'c', 'pending']); + assert.deepEqual( + logs, + variant === 'hydrate' ? ['pending', 'a', 'b', 'c', 'pending'] : ['a', 'b', 'c', 'pending'] + ); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/await-resolve/_config.js b/packages/svelte/tests/runtime-runes/samples/await-resolve/_config.js index 11a645673a..3f718e0c0f 100644 --- a/packages/svelte/tests/runtime-runes/samples/await-resolve/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/await-resolve/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - async test({ assert, target, logs }) { + async test({ assert, target, logs, variant }) { const [b1, b2] = target.querySelectorAll('button'); b1.click(); await Promise.resolve(); @@ -22,6 +22,11 @@ export default test({ `

then b

` ); - assert.deepEqual(logs, ['rendering pending block', 'rendering then block']); + assert.deepEqual( + logs, + variant === 'hydrate' + ? ['rendering pending block', 'rendering then block'] + : ['rendering then block'] + ); } }); diff --git a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md index d53b590de9..004fe10f7c 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md @@ -318,3 +318,24 @@ Since these mismatches are extremely rare, Svelte 5 assumes that the values are {@html markup} ``` + +### `await` blocks delay render + +In Svelte 4, an `{#await ...}` block immediately renders the pending section. In some cases, this is wasteful, because the promise is already resolved. + +In Svelte 5 the block remains unrendered when mounting or updating the promise, until we know whether it is already resolved or not — if so, we initally render then `{:then ...}` or `{:catch ...}` section instead. + +This does _not_ apply during hydration, since the pending section was already server-rendered. + +To wait until the pending section has been rendered (for example during testing), use `await Promise.resolve()` after mounting or updating the promise: + +```diff +let props = { + promise: getPromiseSomehow() +}; + +mount(App, { target, props }); + ++await Promise.resolve(); +assert.equal(target.innerHTML, '...'); +```