4. Chargement asynchrone
De manière générale, il est important de faire attention à la façon dont vous chargez vos données, car cela peut impacter très fortement les performances de votre application.
Par exemple, il est souvent recommandé de charger vos données en parallèle.
Chargement parallèle
Prenons cet exemple :
async function doShopping() {
const fruits = await getFruits(); // prend 2s
const videogames = await getVideoGames(); // prend 2s
console.log('Les courses sont finies'); // s'affiche au bout de 4s
}
Supposons que les fonctions getFruits
et getVideoGames
sont indépendantes. Ici, le log
s'affichera au bout de 4 secondes. Ce chargement est mal optimisé, car on attend la fin de
getFruits
pour commencer getVideoGames
, alors que ces deux requêtes ne dépendent pas l'une de
l'autre.
On appelle ce type de chargement mal optimisé des "cascades".
En JavaScript, si 2 requêtes (autrement dit 2 fonctions aynchrones) sont indépendantes, c'est une
bonne idée de les charger en parallèle. Cela permet d'attendre moins longtemps. Pour cela, vous
pouvez utiliser Promise.all
.
async function doShopping() {
const [fruits, videoGames] = await Promise.all([
getFruits(), // prend 2s
getVideoGames() // prend 2s
];
console.log('Les courses sont finies'); // s'affiche au bout de 2s
}
Chargement différé
Nous pouvons bien sûr appliquer le chargement parallèle à nos fonctions load
, lorsque c'est
pertinent. Mais il reste une situation problématique : parfois, une donnée pas très importante peut
ralentir le chargement d'une page toute entière.
Rappelez-vous : par défaut SvelteKit construit les pages en entier sur le serveur (SSR), et a donc besoin d'attendre sur le serveur le chargement complet des fonctions
load
.
// +page.server.ts
async function load() {
const [main, relevant, secondary] = await Promise.all([
getMainData(), // 2s
getRelevantData(), // 2s
getSecondaryData() // 20s
]);
return {
main,
relevant,
secondary
};
}
Ici, le chargement de secondary
est moins important que les autres données, mais prend plus de
temps. Même avec Promise.all
, le temps de chargement total ne pourra pas être plus court que le
temps maximal de chargement, donc 20s dans notre exemple.
SvelteKit nous permet de résoudre ce problème en renvoyant des données en tant que Promesses.
// +page.server.ts
async function load() {
const [main, relevant] = await Promise.all([
getMainData(), // 2s
getRelevantData() // 2s
]);
const secondary = getSecondaryData(); // ici, on utilise pas 'await', 'secondary' est donc une Promesse
return {
main,
relevant,
secondary
};
}
En n'utilisant pas await
sur les données non nécessaires, nous disons à SvelteKit de ne pas
attendre la fin du chargement des données concernées, et de renvoyer les autres données dès qu'elles
ont fini de charger. Il faudra en revanche attendre les données non nécessaires au niveau de la
page.
<!-- +page.svelte -->
<script>
const { data } = $props();
const { main, relevant, secondary } = $derived(data);
</script>
<p>{main}</p>
<p>{relevant}</p>
{#await secondary}
<p>Chargement des données secondaires..</p>
{:then secondaryData}
<p>{secondaryData}</p>
{/await
Nous avons ici un exemple d'utilisation du bloc logique
#await
.
Une autre option pour charger ces données non essentielles sans alourdir le premier rendu de page serait de faire manuellement un requête côté client. C'est équivalent, même si le chargement dans ce cas sera un peu plus lent, car il faut attendre d'être arrivé sur le client pour commencer le chargement.
Plus de détails sur ce chapitre :