11528 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

J'ai créé un calendrier avec tout un tas de conditions pour prendre en compte les fêtes votives du calendrier romain. Ça marche mais c'est lourd, et j'aimerais savoir si je peux optimiser. Je profite de la présence active de personnes compétentes sur alsa en ce moment Smiley cligne

Voici deux échantillons fonctionnels de mes conditions (pour la gestion des dates j'utilise la librairie Luxon) :
// Immaculée Conception : si le 08/12 est un dimanche, alors célébration le lundi 09/12
if (dayMonth === '0812' && immaculateConceptionDay !== 7 || dayMonth === '0912' && immaculateConceptionDay === 7) data = {name: "Immaculée Conception de la Bienheureuse Vierge Marie", color: "white", grade: "1", rank: "3"}

// Baptême du Seigneur : célébré à la place du 1er dimanche ordinaire, ou le lendemain de l'Épiphanie si celle-ci est célébrée le 7 ou 8 janvier.
if (dayMonth === baptismOfTheLord && epiphany !== ('0701' || '0801') || dayMonth === '0801' && epiphany === '0701' || dayMonth === '0901' && epiphany === '0801') data = {name: "Le Baptême du Seigneur", color: "white", grade: "3", rank: "5"}

EDIT : J'avais posté plus de code au départ mais je ne veux pas vous embrouiller, il ne s'agit que d'une demande d'amélioration des conditions.

S'il y a un truc qui vous choque ne vous gênez pas pour intervenir.
Modifié par Olivier C (27 Nov 2020 - 15:54)
Modérateur
Bonjour,

À mon avis, l'ensemble du calendrier pourrait être traité en 1 seule ligne de moins de 23 caractères ... Nan, je plaisante ! Smiley biggrin

Plus sérieusement, il n'y a sans doute pas grand chose à réduire (ou alors au détriment de la lisibilité du code qu'il ne faut pas négliger). Voici cependant quelques remarques.

1) si tu es sûr que l'on ne peut pas avoir 2 fêtes le même jour (je ne sais pas si c'est vraiment le cas), il vaut mieux faire des if ... else if ... else if ... plutôt que des if ... if ... if ...

L'exécution sera plus rapide puisqu'on arrêtera dès qu'on aura trouvé au lieu de continuer à tester jusqu'au bout.

2) si tu as très peu de "colors" différentes, voire si c'est toujours "white", tu peux ajouter la couleur à l'objet "data" après la série de conditions. Si tu as 50 fêtes pour lesquelles data.color vaut "white", ce serait ballot d'écrire 50 fois color: "white" alors qu'un seul data.color="white"; pourrait suffire.

if (dayMonth === '0812' && immaculateConceptionDay !== 7 || dayMonth === '0912' && immaculateConceptionDay === 7) data = {name: "Immaculée Conception de la Bienheureuse Vierge Marie", grade: "1", rank: "3"};

else if (dayMonth === baptismOfTheLord && epiphany !== ('0701' || '0801') || dayMonth === '0801' && epiphany === '0701' || dayMonth === '0901' && epiphany === '0801') data = {name: "Le Baptême du Seigneur", grade: "3", rank: "5"};

data.color="white";


Tu as peut-être d'autres améliorations du même genre de possible pour grade et rank, en regroupant les tests pour les datas de même grade ou de même rank.

Mais bon, on gagne pas forcément beaucoup et on diminue la clarté du code.

3) dans les conditions, je mettrais des parenthèses un peu partout et je ne ferais pas confiance à mon cerveau pour calculer les priorités des opérateurs. Quand on a beaucoup d'opérateurs dans une condition, on a vite fait de faire une erreur sur leurs priorités.

if (((dayMonth === '0812') && (immaculateConceptionDay !== 7)) || ((dayMonth === '0912') && (immaculateConceptionDay === 7))) data = {name: "Immaculée Conception de la Bienheureuse Vierge Marie", grade: "1", rank: "3"};

Comme ça, t'es sûr de ce que ça fait.

Je signale cependant que mon avis est minoritaire sur ce point.

4) Il n'est pas nécessaire d'employer ici !== et ===. Les opérateurs != et == suffisent.

Certes, y en a qui disent de toujours utiliser === et !==. Je ne suis pas de cet avis (et je ne suis pas le seul).

En particulier quand il s'agit de comparer des nombres ou des chaines de caractères au contenu d'une variable (ce qui est ton cas ici), il n'y a pas de bonnes raisons d'utiliser === et !==.

Par exemple, pour la comparaison entre immaculateConceptionDay et 7, c'est risqué. Si on emploie !==, il faut être sûr avant de faire la comparaison que immaculateConceptionDay est bien un nombre et pas une chaine de caractère : c'est souvent une prise de tête. Or il est clair ici que même si immaculateConceptionDay vaut par inadvertance "7" (et non pas 7), on attend que la comparaison renvoie la même chose que si c'était 7 quand même.

Parfois, c'est encore plus sournois que ça. Par exemple :
var a="a";
var b=new String("b");
var r;
r=(a=="a"); // r vaut true
r=(a==="a"); //  r vaut true
r=(b=="b"); //  r vaut true
r=(b==="b"); //  r vaut false !!!

Ceci veut dire qu'il faudrait être sûr, avant d'utiliser === quand on compare 2 chaines de caractères, qu'elles ont bien été créées de manière "compatible. Pas toujours évident !

Par contre, dans certains cas, il faut privilégier === et !==, mais en pratique, c'est souvent quand l'un des opérateurs vaut false ou l'un de ses nombreux équivalents (0, "", undefined, null, etc...).

5) Pour des éventuelles optimisations des conditions, il faudrait avoir une connaissance plus précise de l'ensemble du projet (par exemple, comment sont calculés immaculateConceptionDay, baptismOfTheLord, ...). En particulier, je me suis demandé pourquoi ne suffit-il pas d'écrire :
if (dayMonth == baptismOfTheLord) data = {name: "Le Baptême du Seigneur", color: "white", grade: "3", rank: "5"};

J'imagine que tu as de bonnes raisons d'avoir écrit des conditions à rallonge. Et si elles sont nécessaires, il y a assez peu de gains à espérer.

Amicalement,
Modifié par parsimonhi (27 Nov 2020 - 20:00)
Meilleure solution
Je te remercie beaucoup pour ce commentaire très enrichissant pour moi. A vrai dire j'espérais ton intervention, très complète. Une intervention substantielle à méditer pour moi, encore une fois.

Pour ta question finale sur mon code, il s'agit de variables mal nommées qui prêtent donc à confusion. Je vais aussi revoir cela (édit., c'est fait : baptismOfTheLord => precomputingBaptismOfTheLord).

Merci pour tout.
Modifié par Olivier C (27 Nov 2020 - 21:41)
Et puis j'ai pas encore fini de m'amuser :
Wikipédia a écrit :
Solennité de Saint Joseph, époux de la Vierge Marie : 19 mars, reporté au 20 mars si le 19 tombe un dimanche de carême, ou avancé au samedi avant les Rameaux si le 19 tombe pendant la semaine sainte.

Pétage de boulon...
Smiley nut Smiley roflol Smiley crash

Edit : ah non mais en fait c'est encore pire que ce que j'imaginais !!! :
Wikipédia v2 a écrit :
Si la fête tombe un dimanche, autre que le Dimanche des Rameaux, celle-ci est célébrée le jour suivant, généralement le lundi 20 mars, mais seulement si une autre solennité (par exemple, un autre Saint patron de l'Église) n'est pas célébrée durant cette journée. Depuis 2008, si le jour de la Fête de Saint Joseph tombe pendant la Semaine Sainte, la célébration de sa fête est déplacée vers le jour le plus proche possible avant le 19 mars, généralement le samedi précédant la Semaine Sainte.

Modifié par Olivier C (27 Nov 2020 - 22:15)
Juste pour laisser une méthode optimale avec Luxon sur le forum :

Les objets dates ne doivent pas être comparés avec `===` (c'est dit dans la doc des librairies telle que Luxon : moyen déconseillé pour les valeurs immutables). Lorsque j'ai voulu optimiser mon calendrier pour pouvoir prendre aussi en compte différents moments dans la journée je suis passé de la comparaison de strings à la comparaison d'objets. Ma méthode ne marchait pas avec les objets (y compris `==`), je ne sais pour quel raison puisque qu'ils semblaient identiques, ce qui m'a conduit à me documenter pour chercher la cause du problème. J'ai ainsi trouvé une fonctionnalité qui fait le taf (et bien plus élégante) :
// old method:
if (date.toFormat('ddMMyyy') === easterDate.plus({days: -46})) data.name = "Mercredi des Cendres"

// new method:
if (easter.plus({days: -46}).hasSame(date, 'day')) data.name = "Mercredi des Cendres"

Modifié par Olivier C (06 Dec 2020 - 05:27)