Hello,

Comme vous le savez, l'image de Boo (la mascotte en haut à gauche des pages) change en fonction de la date et de la météo. Ce mécanisme fait pour l'instant partie du site, mais j'aimerais bien le remplacer pour permettre à ceux qui savent en dessiner d'en ajouter de nouvelles variantes sans avoir besoin de passer par moi. J'envisage de faire ça au moyen d'un site séparé, déployé indépendamment, dont le seul rôle est de définir l'image à afficher et l'éventuelle animation associée. Mon problème c'est que je n'arrive pas à faire ça sans dégrader le rendu du site à cause de clignotements ou de pages plus lentes à charger.

Le fonctionnement aujourd'hui

Actuellement c'est yAronet qui, à chaque affichage de page, peut déterminer quelle variante de Boo afficher et donc insérer directement la bonne URL dans la page. Un JavaScript s'occupe de la partie animation, s'il y a une animation définie pour le Boo sélectionné (par exemple le Boo "arbre de noël" affiché en ce moment). Ce script est chargé de façon asynchrone sur la page, ce qui signifie que l'animation démarre potentiellement que quelques millisecondes après que la page est chargée ce qui ne pose aucun problème puisque les animations sont lissées et sans transitions brutales. Le JavaScript est statique (pour favoriser sa mise en cache), c'est à dire qu'il ne dépend pas du Boo sélectionné. Pour savoir quel Boo est actif, il compare seulement l'URL de l'image avec celles qu'il connait pour savoir si une animation doit être démarrée.

En gros, ça fonctionne comme ça :
Pseudo-code du fonctionnement actuel
Page affichée par yAronet :
<img id="boo" src="boo/noel.png" />
<script type="text/javascript" src="boo/animation.js" async></script>

Script d'animation :
var boo = document.getElementById('boo');

switch (baseNameWithoutExtension(boo.src))
{
    case 'noel':
        startNoelAnimation();
        break;
}
Ça fonctionne bien, avec quand même un petit défaut que j'aimerais résoudre et que j'expliquerai plus tard.

Ce que j'avais envisagé de changer

Comme je le disais plus haut, je pensais déplacer ce fonctionnement dans un site dédié, qui serait responsable de choisir quel Boo afficher et s'occuper de servir à la fois l'image et le code JavaScript. yAronet se contenterait de référencer deux URLs vers ce nouveau service mais ne choisirait plus quel Boo doit être affiché. Voilà à quoi ça pourrait ressembler :
Pseudo-code du fonctionnement envisagé
Page affichée par yAronet :
<img id="boo" src="http://boo.yaronet.org/image.php" />
<script type="text/javascript" src="http://boo.yaronet.org/animation.js" async></script>

Script PHP de sélection d'image "image.php" :
<?php

$boo = selectCurrentBooVariant();

header('Location: http://boo.yaronet.org/boo/' . $boo . '.png');

Le script d'animation resterait inchangé.
Mais ça ne peut pas fonctionner, car le script d'animation ne peut plus savoir quelle variante de Boo a été sélectionnée : la redirection d'URL effectuée dans le script PHP n'affecte pas le DOM de la page, donc quand le JavaScript s'exécute et lit la valeur de boo.src il obtient toujours http://boo.yaronet.org/image.php et non l'image réellement affichée. Il n'y a, à ma connaissance, aucun moyen de savoir qu'une redirection a eu lieu ni vers quelle URL. De même, impossible de lire les métadonnées de l'image une fois chargée pour savoir de laquelle il s'agit. Tout au plus je pourrais lire ses dimensions et essayer d'en déduire de laquelle il s'agit, mais ça serait très peu fiable (d'autant plus que la plupart des images actuelles font 75x75 pixels).

Le problème des deux requêtes

Le problème que je viens d'identifier peut se résumer facilement : je dois faire deux requêtes (une pour l'image et une pour le JavaScript) dont une seule va calculer quel Boo doit être affiché, mais l'autre doit pouvoir en tenir compte. Cette contraire vient du fait que ce calcul n'est pas gratuit (je fais appel à deux APIs dont le nombre de requêtes est limité pour connaître la météo) donc je ne peux pas le faire en double. D'autre part, même si je le faisais en double je risquerais d'avoir deux réponses différentes (par exemple lors d'un changement d'heure ou à la seconde précise où la météo change) et donc d'avoir des incohérences entre les résultats des deux requêtes.

En pratique il y a déjà une mise en cache de 15 minutes pour éviter d'appeler ces APIs à chaque page, mais je ne vois pas comment partager ce cache entre les deux requêtes. Si me débrouille par exemple pour que image.php écrive un cookie qui pourra être lu par le code JavaScript ça ne fonctionne pas, puisque le cookie se retrouverait sur le domaine boo.yaronet.org tandis que le script s'exécute sur www.yaronet.com. Des iframes ne sont pas envisageables puisque la taille de Boo n'est pas connue à l'avance.

Mes autres pistes clignotent

Bon, si je pars du principe qu'une seule de mes deux requêtes peut déterminer quel Boo à afficher et que la seconde doit se débrouiller pour le déduire sans refaire les calculs, ça limite pas mal mes options. Au lieu d'avoir une image dynamique et un script statique je peux faire l'inverse : générer un code JavaScript qui connait l'URL du Boo à afficher, et qui s'occupe de provoquer le chargement de la bonne image quand il s'exécute :
Pseudo-code de la solution avec JavaScript dynamique
Page affichée par yAronet :
<img id="boo" />
<script type="text/javascript" src="boo/animation.php" async></script>

Code PHP d'animation :
<?php

// On calcule le Boo à afficher et on construit dynamiquement le code JavaScript adapté
$boo = selectCurrentBooVariant();

$code = "var boo = document.getElementById('boo');

boo.src = 'http://boo.yaronet.org/boo/" . $boo . ".png';

switch (baseNameWithoutExtension(boo.src)) /* On pourrait même évaluer ce switch dès maintenant, mais ça ne simplifierait pas le problème */
{
    case 'noel':
        startNoelAnimation();
        break;
}";

// On envoie le tout comme s'il s'agissait d'un JavaScript
header('Content-Length: ' . strlen($code));
header('Content-Type: text/javascript');

echo $code;
Cette fois ça fonctionne, mais le résultat est assez moche car le script s'exécute de façon asynchrone, donc la page est chargée entièrement avant que Boo n'apparaisse : ça clignote. On pourrait enlever l'attribut "async" du script et tant pis pour le temps de chargement de la page, mais ça ne change pas grand chose car même si le script tourne de façon synchrone la modification qu'il provoque sur le DOM ne l'est pas, donc le clignotement persiste.

En plus je n'ai pas tellement envie de faire ça, parce que déterminer quel Boo afficher prend quand même le temps de faire les appels à deux APIs (c'est à dire de l'ordre de quelques centaines de millisecondes). Ça n'arrive qu'une seule fois toutes les 15 minutes et le reste du temps tout est en cache donc l'affichage est quasi-instantané, mais j'aimerais quand même bien ne pas impacter le chargement de la page avec ça. Au passage, c'est le seul petit défaut de la solution actuelle que j'essaie de corriger au passage.

Bloqué !

Je pense que j'ai résumé mes tentatives actuelles, et pour le moment je bloque un peu. Est-ce que vous voyez une autre piste ? C'est rageant d'être bloqué pour un détail qui semble aussi simple smile
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Zeph (./1) :
Si me débrouille par exemple pour que <span class="fixed">image.php</span> écrive un cookie qui pourra être lu par le code JavaScript ça ne fonctionne pas, puisque le cookie se retrouverait sur le domaine <span class="fixed">boo.yaronet.org</span> tandis que le script s'exécute sur <span class="fixed">www.yaronet.com</span>.
Pourquoi ne pas mettre les deux sur le même domaine, avec si besoin des sous-domaines différents ?

Sinon, tu peux utiliser du partage de ressource de différentes origines en autorisant tes domaines à partager leurs cookies.

(C'est pas très joli ces span dans la citation, mais je ne juge pas.)
avatar
Ah tiens, c'est la conséquence de la migration des citations en JS, j'avais prévenu qu'il risquerait d'y avoir des problèmes embarrassed (mais c'est moche en effet)

Sinon oui pourquoi pas le mettre sur le même domaine, ça me semblait dommage d'envoyer spontanément à ce script toutes les infos du domaine yaronet.com (dont les cookies) alors qu'il n'en a pas besoin, mais faute de mieux c'est peut-être le moins pire en effet smile
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Alors je ne sais pas si c'est possible, mais voici une idée :
- ajouter un identifiant dans les requêtes qui change à chaque page affichée, mais qui soit le même pour les deux requêtes (image et animation) d'une même page
- utiliser du PHP à la fois pour l'image et pour l'animation
- avoir un nouveau cache côté serveur (distinct de celui existant, qui est conservé pour limiter le nombre de requêtes) qui soit partagé pour les deux types de requêtes
- à la première requête qui comporte un nouvel identifiant, déterminer le Boo à afficher avec le cache existant, et ajouter la paire Boo/identifiant au nouveau cache
- pour toutes les requêtes suivantes qui comportent le même identifiant (normalement, une seule), utiliser uniquement le nouveau cache pour déterminer le Boo concerné

Ça suppose que :
- on puisse ajouter un nouveau cache, et le partager entre les requêtes
- le cache ne grandisse pas démesurément (mais sa durée de rétention peut être très courte : au pire il y a quoi, 10 secondes maximum entre deux requêtes qui doivent être corrélées ?)
- on puisse avoir un identifiant unique dans chaque page générée sans pourrir les caches

(c'est pourtant vrai que la gestion du cache c'est l'un des problèmes les plus tordus de l'info grin)
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo
Et pourquoi ne pas résoudre le "problème" du clignotement avec une animation CSS ? Chargement différé, mais apparition toute en douceur smile
avatar
./4 Ça ne va pas fonctionner si le serveur parallélise les traitements. Il y a un risque que les deux requêtes arrivent presque simultanément et que le serveur les donne à traiter à deux processus en parallèle. Il ne serait alors pas possible de récupérer les données de session d'une requête pour l'autre. Une solution serait de supprimer ce parallélisme dans la configuration du serveur, mais ça réduirait les performances (ce n'est peut-être pas grave si ce n'est utilisé que pour les Boo et que le traitement est rapide (ce qui n'est pas forcément le cas pour une requête météique)), et ce n'est pas forcément possible suivant l'hébergeur. Sinon, il faudra utiliser un sémaphore.
avatar
./4 : comme dit RHJPP il y a un risque de race condition, et surtout ça va empêcher la mise en cache côté client donc multiplier le poids moyen des pages par 2 ; même si techniquement ça fonctionne, je pense que c'est un trop gros coût à payer pour une fonctionnalité de décoration :/
./5 : je ne pense pas que ça résolve le problème, au lieu de charger une image + un JS qui doivent être synchronisés il faut une image + une CSS ? (l'animation en JS est fluide, c'est le fait de tout générer en JS pour éviter les deux requêtes qui provoque un clignotement smile)
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Zeph (./7) :
je pense que c'est un trop gros coût à payer pour une fonctionnalité de décoration :/
Je m'en doutais un peu, à vrai dire ^^
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo
La solution proposée en ./2 est en place, ça semble fonctionner tout à fait bien, merci smile
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Mais ça ne va pas marcher chez ceux qui bloquent les cookies embarrassed

(je plaisante hein, même moi j'ai mis une exception pour yN ^^)
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo
Bah ils auront également du mal à s'authentifier, et comme Boo ne change que pour les utilisateurs identifiés c'est pas trop grave grin
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Si on peut faire clignoter des trucs (par effet de bord) que pensez vous de remettre une balise <blink> ?
avatarWebmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca
49593.gif
avatar