await
Depuis la version 5.36 de Svelte, vous pouvez le mot-clé await
dans vos composants à trois
endroits où ce n’est pas possible précédemment :
- à la racine du
<script>
de votre composant - dans des déclarations
$derived(...)
- dans votre markup
Cette fonctionnalité est actuellement expérimentale, et vous devez l’activer en ajoutant l’option
experimental.async
là où vous configurez Svelte, en général
svelte.config.js
:
export default {
compilerOptions: {
experimental: {
async: boolean;
};
}
compilerOptions: {
experimental: {
async: boolean;
}
experimental: {
async: boolean
async: true
}
}
};
Le drapeau expérimental sera supprimé avec Svelte 6.
Mises à jour synchronisées
Lorsqu’une expression await
dépend d’un morceau d’état particulier, les changements de cet état ne
seront pas reflétés dans l’interface avant que le travail asynchrone ne soit terminé, afin que
l’interface ne soit pas laissée dans un état inconsistant. En d’autres mots, dans un exemple comme
celui-ci...
<script>
let a = $state(1);
let b = $state(2);
async function add(a, b) {
await new Promise((f) => setTimeout(f, 500)); // délai artificiel
return a + b;
}
</script>
<input type="number" bind:value={a}>
<input type="number" bind:value={b}>
<p>{a} + {b} = {await add(a, b)}</p>
... si vous incrémentez a
, le contenu de <p>
ne sera pas immédiatement mis à jour et
n’affichera donc pas ceci —
<p>2 + 2 = 3</p>
— mais à la place, le texte affichera 2 + 2 = 4
lorsque add(a, b)
sera résolue.
Les mises à jour peuvent se superposer — une mise à jour rapide sera reflétée dans l’interface tandis qu’une mise à jour lente sera toujours en cours.
Concurrence
Svelte fera autant de travail asynchrone que possible en parallèle. Par exemple, si vous avez deux
expressions await
dans votre markup...
<p>{await one()}</p>
<p>{await two()}</p>
... les deux fonctions seront exécutées en mêmet temps, puisque ce sont des expressions indépendantes, même si elles sont visuellement séquentielles.
Ceci ne s’applique pas aux expressions await
de votre <script>
ou dans les fonctions asynchrones
— celles-ci s’exécutent comme tout autre code JavaScript asynchrone. Toutefois, il y a une
exception : les expressions $derived
indépendantes seront mises à jour indépendamment, même si
elles sont exécutées séquentiellement lors de leur création :
// ces expressions sont exécutées séquentiellement la première fois
// mais seront mises à jour indépendamment
let let a: number
a = function $derived<number>(expression: number): number
namespace $derived
Declares derived state, i.e. one that depends on other state variables.
The expression inside $derived(...)
should be free of side-effects.
Example:
let double = $derived(count * 2);
$derived(await function one(): Promise<number>
one());
let let b: number
b = function $derived<number>(expression: number): number
namespace $derived
Declares derived state, i.e. one that depends on other state variables.
The expression inside $derived(...)
should be free of side-effects.
Example:
let double = $derived(count * 2);
$derived(await function two(): Promise<number>
two());
Si vous écrivez du code comme celui-là, attendez-vous à ce que Svelte vous affiche un avertissement
await_waterfall
Indiquer les états de chargement
Pour afficher des interfaces par défaut, vous pouvez entourer le contenu dans une balise
<svelte:boundary>
ayant un snippet pending
. Ce contenu
sera affichée lorsque la frontière sera créée pour la première fois, mais pas lors des mises à jour
suivantes, qui seront globalement coordonnées.
Après que le contenu d’une frontière a été résolu pour la première fois et que son snippet pending
a été remplacé, vous pouvez détecter les tâches asynchrones suivantes avec
$effect.pending()
. C’est ce qu’il vous faudra utiliser pour afficher
une icône de chargement à côté d’un champ de formulaire, par exemple.
Vous pouvez aussi utiliser settled()
pour obtenir une promesse qui se résout
lorsque la mise à jour actuelle se termine :
import { function tick(): Promise<void>
Returns a promise that resolves once any pending state changes have been applied.
tick, function settled(): Promise<void>
Returns a promise that resolves once any state changes, and asynchronous work resulting from them,
have resolved and the DOM has been updated
settled } from 'svelte';
async function function onclick(): Promise<void>
onclick() {
let updating: boolean
updating = true;
// sans ceci, le changement à `updating` sera groupé
// avec les autres changements, signifiant qu'il ne sera
// pas reflété dans l'interface
await function tick(): Promise<void>
Returns a promise that resolves once any pending state changes have been applied.
tick();
let color: string
color = 'octarine';
let answer: number
answer = 42;
await function settled(): Promise<void>
Returns a promise that resolves once any state changes, and asynchronous work resulting from them,
have resolved and the DOM has been updated
settled();
// toute mise à jour affectée par `color` ou `answer`
// a désormais été appliquée
let updating: boolean
updating = false;
}
Gestion des erreurs
Les erreurs dans les expressions await
vont remonter jusqu’à la frontière
d’erreur la plus proche.
Rendu côté serveur
Svelte supporte le rendu côté serveur (SSR) asynchrone avec l’API render(...)
. Pour vous en
servir, contentez-vous d’utiliser await
pour récupérer la valeur de retour :
import { function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
props?: Omit<Props, "$$slots" | "$$events">;
context?: Map<any, any>;
idPrefix?: string;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
props: Omit<Props, "$$slots" | "$$events">;
context?: Map<any, any>;
idPrefix?: string;
}]): RenderOutput
Only available on the server and when compiling with the server
option.
Takes a component and returns an object with body
and head
properties on it, which you can use to populate the HTML when server-rendering your app.
render } from 'svelte/server';
import type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App from './App.svelte';
const { const head: string
HTML that goes into the <head>
head, const body: string
HTML that goes somewhere into the <body>
body } = await render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
...;
} | undefined): RenderOutput
Only available on the server and when compiling with the server
option.
Takes a component and returns an object with body
and head
properties on it, which you can use to populate the HTML when server-rendering your app.
render(const App: LegacyComponentType
App);
Si vous utilisez un framework comme SvelteKit, ceci est déjà fait pour vous.
Si une <svelte:boundary>
ayant un snippet pending
est détectée lors du SSR, ce snippet sera
rendu tandis que le reste du contenu sera ignoré. Toutes les expressions await
rencontrées en
dehors de frontières ayant des snippets pending
seront résolues et leur contenu sera rendu avant
de renvoyer le résultat de await render(...)
.
Dans le futur, nous prévoyons d’ajouter une implémentation de streaming permettant de rendre du contenu en toile de fond.
Mises en garde
En tant que fonctionnalité expérimentale, les détails de comment les expressions await
sont gérées
(ainsi que les APIs liées comme $effect.pending()
) sont potentiellement sujettes à des breaking
changes en dehors d’un changement de version majeur, même si nous avons l’intention de limiter ces
changements au minimum.
Breaking changes
Les effets sont exécutées dans un ordre légèrement différent lorsque l’option experimental.async
est à true
.
Spécifiquement, les effets de block comme {#if ...}
et {#each ...}
s’exécutent désormais avant
un $effect.pre
ou un beforeUpdate
du même composant, ce qui implique que dans de très rares
situations
il est possible de mettre à jour un bloc qui ne devrait pas exister, mais uniquement si vous mettez
à jour un état au sein d’un effet, ce que vous devriez éviter.
Modifier cette page sur Github llms.txt