Lorsque l’on débute avec Google Apps Script, on fait face à une énigme qui déroute de nombreux développeurs : pourquoi les choses ne s’affichent-elles pas dans l’ordre où on les a programmées ?
Vous écrivez un script simple pour effectuer une action A, puis B, puis C. Vous vous attendez à voir chaque résultat apparaître l’un après l’autre. Mais à la place, vous attendez, et tout s’affiche d’un seul coup à la toute fin. C’est frustrant, n’est-ce pas ?
La clé pour résoudre ce mystère réside dans la compréhension de l’interaction entre votre feuille Google Sheets (dans votre navigateur) et le script qui s’exécute, lui, sur les serveurs de Google.
Plongeons dans un exemple simple pour illustrer ce phénomène.
Le script qui défie la logique
Imaginons le script suivant. Prenez une seconde pour lire le code et deviner ce qu’il va faire.
function testerOrdreExecution() {
const feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
feuille.getRange("A1").setValue("Valeur 1 à " + new Date());
SpreadsheetApp.getUi().alert("Popup 1");
feuille.getRange("A2").setValue("Valeur 2 à " + new Date());
SpreadsheetApp.getUi().alert("Popup 2");
feuille.getRange("A3").setValue("Valeur 3 à " + new Date());
SpreadsheetApp.getUi().alert("Popup 3");
}
Ce à quoi on s’attend logiquement :
- Le texte « Valeur 1 à… » apparaît immédiatement dans la cellule A1.
- Une boîte de dialogue affiche « Popup 1 ». On clique sur OK.
- Le texte « Valeur 2 à… » apparaît immédiatement dans la cellule A2.
- Une boîte de dialogue affiche « Popup 2 ». On clique sur OK.
- Le texte « Valeur 3 à… » apparaît immédiatement dans la cellule A3.
- Une boîte de dialogue affiche « Popup 3 ». On clique sur OK.
Ce qui se passe en réalité :
Lorsque nous exécutons ce script, le résultat est très différent.
- La boîte de dialogue « Popup 1 » apparaît. Nous cliquons sur OK.
- …Rien ne se passe dans la feuille. Elle reste vide.
- Puis la « Popup 2 » apparaît. On clique.
- Encore rien.
- Puis la « Popup 3 » !
- Ce n’est qu’après avoir validé cette troisième et dernière alerte que toutes les valeurs apparaissent dans les cellules, exactement au même moment.
Les horodatages dans les cellules prouvent bien que les opérations ont été réalisées à quelques secondes d’intervalle, mais l’affichage, lui, a été simultané. Pourquoi ?
Tout est une question de serveur
L’information cruciale à retenir est la suivante : votre script Apps Script s’exécute sur les serveurs de Google, pas dans votre navigateur.
Imaginez que vous avez un assistant dans la pièce d’à côté. Vous lui donnez une liste de tâches à accomplir :
- Écris « Valeur 1 » sur le tableau blanc.
- Montre-moi un panneau « Popup 1 » et attends mon « pouce levé » pour continuer.
- Écris « Valeur 2 » sur le tableau blanc.
- Montre-moi un panneau « Popup 2 » et attends mon « pouce levé ».
- Écris « Valeur 3 » sur le tableau blanc.
- Montre-moi un panneau « Popup 3 » et attends mon « pouce levé ».
L’assistant exécute chaque tâche dans le bon ordre. Mais il ne vient pas vous montrer le tableau blanc après chaque modification. Ce serait une perte de temps. Il est beaucoup plus efficace pour lui de terminer la liste complète des tâches et de ne vous montrer le tableau blanc qu’une seule fois, à la toute fin, avec le résultat final.
C’est exactement ce que fait le serveur de Google. Pour optimiser les performances et économiser les ressources, il regroupe toutes les modifications de l’interface utilisateur (les écritures dans votre feuille) et les envoie à votre navigateur en une seule mise à jour, une fois que le script est complètement terminé.
La solution : Forcer la mise à jour avec flush()
Alors, comment demander à notre assistant de nous montrer son travail en cours ? Comment forcer la feuille de calcul à se mettre à jour quand nous le voulons ?
La solution est simple : nous utilisons la commande SpreadsheetApp.flush().
La méthode flush() est l’équivalent de dire à notre assistant : « Arrête tout ce que tu fais et montre-moi le tableau blanc maintenant ! » Elle force le serveur de Google à appliquer immédiatement toutes les modifications visuelles en attente à notre feuille.
Modifions notre script en ajoutant flush() après chaque écriture :
function testerOrdreAvecFlush() {
const feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
feuille.getRange("A1").setValue("Valeur 1 à " + new Date());
SpreadsheetApp.flush(); // On force la mise à jour visuelle !
SpreadsheetApp.getUi().alert("Popup 1");
feuille.getRange("A2").setValue("Valeur 2 à " + new Date());
SpreadsheetApp.flush(); // On force la mise à jour visuelle !
SpreadsheetApp.getUi().alert("Popup 2");
feuille.getRange("A3").setValue("Valeur 3 à " + new Date());
SpreadsheetApp.flush(); // On force la mise à jour visuelle !
SpreadsheetApp.getUi().alert("Popup 3");
}
Maintenant, lorsque nous exécutons cette nouvelle version, nous obtenons exactement le comportement attendu : Valeur 1, Popup 1, Valeur 2, Popup 2, Valeur 3, Popup 3. L’ordre est enfin respecté.
Un cas d’usage concret : Le vérificateur de statut
Imaginez une feuille avec une liste d’URL de sites web dans la colonne A. Nous voulons un script qui vérifie si chaque site est en ligne et écrit « En ligne » ou « Erreur » dans la colonne adjacente. Chaque vérification prenant quelques secondes, il est bien plus agréable pour l’utilisateur de voir les résultats s’afficher en temps réel plutôt que d’attendre la fin.
Pour que vous puissiez tester par vous-même, mettons en place notre feuille de calcul. Dans la première colonne (A), créez un en-tête « URLs » en A1, puis collez une liste de sites web en dessous.
Voici les trois fonctions que nous allons comparer. Vous pouvez les ajouter dans l’éditeur de script (Extensions > Apps Script).
1. Approche Ligne par Ligne (Lente mais visuelle)
Cette fonction vérifie chaque URL, écrit le statut dans la colonne B, puis force immédiatement la mise à jour de l’affichage avec flush(). C’est l’approche la plus conviviale pour l’utilisateur.
/**
* Vérifie les URLs une par une et met à jour la feuille après chaque ligne.
* Expérience utilisateur : excellente, on voit la progression en temps réel.
* Performance : la plus lente.
*/
function verifierStatutLigneParLigne() {
const feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const plageUrls = feuille.getRange("A2:A" + feuille.getLastRow());
const urls = plageUrls.getValues();
for (let i = 0; i < urls.length; i++) {
const url = urls[i][0];
let statut = "";
if (url) { // On ne traite que les cellules non vides
try {
// L'option muteHttpExceptions permet de traiter les erreurs (ex: 404) comme des réponses valides
UrlFetchApp.fetch(url, { 'muteHttpExceptions': true });
statut = "En ligne";
} catch (e) {
statut = "Erreur";
}
}
// Écrit le résultat dans la colonne B pour la ligne actuelle
feuille.getRange(i + 2, 2).setValue(statut);
// La ligne cruciale : on force l'affichage après chaque vérification
SpreadsheetApp.flush();
}
}
2. Approche par lots (Le bon compromis)
Ici, nous utilisons l’opérateur modulo (%) pour déclencher flush() tous les 10 sites vérifiés. Cela réduit considérablement le nombre d’appels au serveur tout en fournissant un retour visuel régulier.
/**
* Vérifie les URLs et met à jour l'affichage par lots de 10.
* Expérience utilisateur : bonne, on voit la progression par blocs.
* Performance : bien meilleure que la première approche.
*/
function verifierStatutParLots() {
const feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const plageUrls = feuille.getRange("A2:A" + feuille.getLastRow());
const urls = plageUrls.getValues();
const TAILLE_LOT = 10;
for (let i = 0; i < urls.length; i++) {
const url = urls[i][0];
let statut = "";
if (url) {
try {
UrlFetchApp.fetch(url, { 'muteHttpExceptions': true });
statut = "En ligne";
} catch (e) {
statut = "Erreur";
}
}
// Écrit le résultat dans la colonne C
feuille.getRange(i + 2, 3).setValue(statut);
// Si on a traité un lot de 10, ou si c'est la dernière URL de la liste...
if ((i + 1) % TAILLE_LOT === 0 || (i + 1) === urls.length) {
// ... on force la mise à jour !
SpreadsheetApp.flush();
}
}
}
3. Approche « Tout en une fois » (La plus performante)
C’est la méthode la plus rapide et la plus optimisée. Le script traite toutes les URLs en mémoire, stocke les résultats dans un tableau, et n’effectue qu’une seule opération d’écriture à la toute fin avec setValues(). Il n’y a aucun retour visuel avant la fin, mais le temps d’exécution est minimal.
/**
* Vérifie toutes les URLs, puis écrit TOUS les résultats en une seule fois.
* Expérience utilisateur : aucune, l'utilisateur attend la fin.
* Performance : la plus rapide. C'est une bonne pratique pour les gros volumes de données.
*/
function verifierStatutEnUneFois() {
const feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const plageUrls = feuille.getRange("A2:A" + feuille.getLastRow());
const urls = plageUrls.getValues();
const statuts = []; // On prépare un tableau pour stocker les résultats
for (let i = 0; i < urls.length; i++) {
const url = urls[i][0];
let statutFinal = "";
if (url) {
try {
UrlFetchApp.fetch(url, { 'muteHttpExceptions': true });
statutFinal = "En ligne";
} catch (e) {
statutFinal = "Erreur";
}
}
// On ajoute le statut au tableau, sans toucher à la feuille de calcul
statuts.push([statutFinal]);
}
// Une fois toutes les URLs vérifiées, on écrit tout le tableau d'un seul coup
// dans la colonne D. C'est extrêmement rapide.
feuille.getRange(2, 4, statuts.length, 1).setValues(statuts);
}
Comment exécuter le code facilement ?
Pour faciliter le test, vous pouvez ajouter un menu personnalisé à votre feuille. Ajoutez cette fonction à votre script :
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('🏁 Vérificateur de Statut')
.addItem('Ligne par ligne (Lent)', 'verifierStatutLigneParLigne')
.addItem('Par lots de 10 (Moyen)', 'verifierStatutParLots')
.addItem('Tout en une fois (Rapide)', 'verifierStatutEnUneFois')
.addToUi();
}
Enregistrez votre script et actualisez votre feuille de calcul. Un nouveau menu « 🏁 Vérificateur de Statut » apparaîtra, vous permettant de lancer chaque fonction et de comparer en direct leur comportement et leur vitesse !
Conclusion
Vous venez de maîtriser l’un des concepts les plus fondamentaux et les plus déroutants de Google Apps Script. En comprenant que votre script s’exécute sur un serveur qui optimise les mises à jour visuelles, vous comprenez maintenant pourquoi ce décalage existe.
Avec la méthode SpreadsheetApp.flush() dans votre arsenal, vous pouvez désormais choisir consciemment entre une performance maximale et une expérience utilisateur améliorée, en adaptant le comportement de vos scripts à chaque situation. Bon codage !