Améliorer la réactivité de l’interface web commence souvent par optimiser la manière dont votre frontend communique avec le backend. Dans notre Semaphore UI basé sur Vue.js, nous avons introduit plusieurs techniques pour rendre le chargement des données plus rapide et plus fluide pour les utilisateurs. Cet article partage les trois changements les plus impactants que nous avons mis en œuvre dans la version 2.14.
Pourquoi optimiser l’utilisation des API ?
Les API sont souvent la colonne vertébrale des applications web dynamiques, mais des requêtes mal gérées peuvent créer des goulets d’étranglement. De longs temps d’attente pour des appels séquentiels ou des récupérations de données redondantes dégradent l’expérience utilisateur. Abordons ces problèmes de front.
1. Requêtes parallèles avec Promise.all()
Le problème : Requêtes séquentielles
Un piège courant est de faire des appels API un après l’autre. Par exemple, récupérer les détails de l’utilisateur, puis ses commandes, puis ses préférences :
// Approche séquentielle (lente 😞)
async function fetchData() {
const user = await getUser();
const inventory = await getInventory(projectID);
const templates = await getTemplates(projectID);
return { user, inventory, templates };
}
Ici, chaque requête attend que la précédente se termine. Si chaque appel prend 200 ms, le total est de 600 ms—un retard notable.
La solution : Exécution parallèle
Vue.js tire parti des capacités asynchrones de JavaScript, nous pouvons donc lancer plusieurs requêtes simultanément en utilisant Promise.all()
:
// Approche parallèle (rapide ⚡)
async function fetchDataParallel() {
const [user, inventory, templates] = await Promise.all([
getUser(),
getInventory(projectID),
getTemplates(projectID),
]);
return { user, inventory, templates };
}
En regroupant les requêtes indépendantes, les trois appels se résolvent simultanément. Si chacun prend 200 ms, le total tombe à 200 ms !
Intégration avec Vue
Dans un composant Vue, utilisez ce modèle dans les hooks de cycle de vie ou les méthodes :
export default {
props: {
projectID: Number,
},
watch: {
async projectID() {
await this.fetchDataParallel();
},
},
async created() {
await this.fetchDataParallel();
},
methods: {
async fetchDataParallel() {
try {
const [
this.user,
this.inventory,
this.templates
] = await Promise.all([
getUser(),
getInventory(this.projectID),
getTemplates(this.projectID),
]);
} catch (error) {
console.error("Échec du chargement des données :", error);
}
};
}
Astuce : Combinez cela avec des loaders squelettes pour garder les utilisateurs engagés pendant le chargement des données.
2. Réutilisation des réponses API mises en cache
Le problème : Récupération redondante
Les applications re-récupèrent souvent les mêmes données à travers les composants (par exemple, les données de profil utilisateur demandées par plusieurs vues). Cela gaspille de la bande passante et ralentit l’interface.
La solution : Mise en cache et réutilisation
Stockez les réponses API et réutilisez-les jusqu’à ce qu’elles soient invalidées. Le système de réactivité de Vue facilite cela avec un store centralisé (comme Pinia ou Vuex) :
Étape 1 : Créer un store de cache
// stores/apiCache.js
import { defineStore } from 'pinia';
export const useApiCache = defineStore('apiCache', {
state: () => ({
project: null,
templates: {},
}),
actions: {
async fetchProject() {
if (!this.project) {
this.project = await getProject();
}
return this.project;
},
async fetchTemplates(id) {
if (!this.templates[id]) {
this.templates[id] = await fetchTemplates(id);
}
return this.templates[id];
},
},
});
Étape 2 : Utiliser le Store dans les Composants
// Component.vue
import { useApiCache } from '@/stores/apiCache';
export default {
setup() {
const apiCache = useApiCache();
// Réutilise l'utilisateur mis en cache ou le récupère une fois
const user = apiCache.fetchUser();
return { user };
},
};
Astuce : Dans Semaphore UI, nous n’utilisons pas encore Pinia, mais nous prévoyons de migrer vers cela bientôt.
Stratégies d’invalidation du cache
- Expiration basée sur le temps : Supprimez les données mises en cache après une durée définie.
- Déclencheurs manuels : Invalidez après des mutations (par exemple, lorsqu’un utilisateur met à jour son profil).
- Réactivité de Vue : Réinitialisez les données lorsque l’état de l’application change (comme lors de la déconnexion).
3. Utilisation de loaders squelettes pour des transitions plus fluides
Le problème : UI non réactive pendant le chargement
Même avec des appels API optimisés, les utilisateurs font toujours face à de brèves attentes pendant que les données se chargent. Des écrans vides ou des interfaces gelées pendant ce temps peuvent donner à votre application un aspect peu soigné ou lent, même si le temps de récupération réel est minime.
La solution : Loaders squelettes
Les espaces réservés squelettes imitent la mise en page de votre contenu pendant le chargement des données, fournissant un retour visuel qui garde les utilisateurs engagés. Combinés avec des requêtes parallèles et la mise en cache, ils créent une perception de vitesse sans faille.
Comment ajouter des loaders squelettes dans Vue.js
Étape 1 : Choisir le composant squelette
Dans Semaphore UI, nous utilisons le framework Vuetify. Il inclut déjà un composant de loader squelette.
<v-skeleton-loader
type="
table-heading,
image,
list-item-two-line,
list-item-two-line,
list-item-two-line"
></v-skeleton-loader>
Étape 2 : Intégrer avec le chargement de données asynchrone Utilisez un état de chargement pour basculer entre les squelettes et le contenu réel :
// Component.vue
export default {
data() {
return {
isLoading: true,
user: null,
templates: [],
};
},
async created() {
this.isLoading = true;
try {
[this.user, this.templates] = await Promise.all([
fetchUser(),
fetchTemplates(),
]);
} finally {
this.isLoading = false;
}
},
};
Étape 3 : Rendre conditionnellement les squelettes
<template>
<div class="user-profile">
<v-skeleton-loader
v-if="isLoading"
type="
table-heading,
image,
list-item-two-line,
list-item-two-line,
list-item-two-line"
></v-skeleton-loader>
<v-card v-else>
<h2>{{ user.name }}</h2>
<v-card v-for="tpl in templates" :key="tpl.id">
<v-card-title>{{ tpl.name }}</v-card-title>
<v-card-text>{{ tpl.description }}</v-card-text>
</v-card>
</div>
</div>
</template>
Conseils avancés pour la conception de loaders
- Correspondre à la structure du contenu : Concevez des squelettes pour refléter votre mise en page réelle (par exemple, des espaces réservés pour les images, des lignes de texte).
- Prioriser le contenu au-dessus de la ligne de flottaison : Affichez d’abord les loaders pour le contenu visible pendant que les données de fond se chargent.
- Combiner avec la mise en cache : Si des données mises en cache existent, sautez les squelettes et montrez les données immédiatement.
Pourquoi cela compte
- Expérience utilisateur : 74 % des utilisateurs remarquent les temps de chargement (PWA Stats).
- Performance perçue : Les loaders font que les attentes semblent 15-30 % plus courtes (Recherche NNGroup).
- Confiance dans la marque : Des transitions soignées signalent le professionnalisme.
Mettre le tout ensemble
En combinant requêtes parallèles, mise en cache intelligente, et loaders squelettes, nous avons pu réaliser des améliorations significatives :
- Chargements initiaux plus rapides : Les requêtes parallèles réduisent considérablement les temps de chargement des données.
- Navigation plus fluide : Les réponses réutilisées réduisent les appels réseau redondants.
- Engagement utilisateur amélioré : Les loaders squelettes améliorent le retour visuel et la vitesse perçue.
Optimiser l’utilisation des API ne concerne pas seulement la performance brute—cela améliore également l’expérience utilisateur. Nous continuerons à affiner notre frontend pour rendre Semaphore UI plus rapide et plus convivial à chaque mise à jour.