Skip to main content

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 :

svelte.config
export default {
	
compilerOptions: {
    experimental: {
        async: boolean;
    };
}
compilerOptions
: {
experimental: {
    async: boolean;
}
experimental
: {
async: booleanasync: 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: numbera = 
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);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(await function one(): Promise<number>one());
let let b: numberb =
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);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$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

@since5.36
settled
} from 'svelte';
async function function onclick(): Promise<void>onclick() { let updating: booleanupdating = 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: stringcolor = 'octarine'; let answer: numberanswer = 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

@since5.36
settled
();
// toute mise à jour affectée par `color` ou `answer` // a désormais été appliquée let updating: booleanupdating = 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 :

server
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 &#x3C;head>

head
, const body: string

HTML that goes somewhere into the &#x3C;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: LegacyComponentTypeApp);

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

précédent suivant