Javascript et les trois manières de faire un IF

La syntaxe du javascript n’est régie par aucune norme prédéfinie, ainsi n’importe qui peut programmer de la manière qu’il veut.

Pour ma part ces derniers temps je  me suis penché sur l’optimisation de mon code javascript en me basant sur trois points :

  • gagner du temps en programmant => code simple à écrire, facilement lisible pour y revenir plus tard
  • optimisation de la vitesse d’exécution du code
  • diminution de la taille de notre javascript => les compresseurs automatiques existent, mais leurs algorithmes ne permettent pas de tout réduire, un code faisant 150ko pourra être réduit à 40ko, mais ce même code programmé d’une autre façon pourra très bien être réduit à 30ko. Bien entendu, nous ne sommes plus aussi attentif qu’avant sur la taille de nos fichiers grâce à l’ADSL, mais n’oublions pas nos clients mobile, et surtout la charge en moins que la bande passante de notre serveur évitera.

Les Trois « if »

Afin de connaitre facilement duquel on parle dans la suite de l’article, j’ai décidé de les nommer de cette façon : if explicite, if implicite et if ternaire. Je rajouterai bientôt le Switch dans ces graphiques.

Attention tout de même, ils ne permettent pas tous la même chose !

If Explicite

Bon celui-là tout le monde le connait, et si vous ne le connaissez pas, je pense que vous vous êtes trompé de site :P !

if ( variable1 === 'valeur 1' ) {
//alors
} else {
//sinon
}

« Ah ah, le noob… il a même pas mit les elseif !!! »
En fait les « else if » sont simplement des « else » ou dans le bloc nous avons un « if », mais comme vous le savez, nous pouvons omettre les accolades lorsque le bloc suivant ne contient qu’une instruction.

Ainsi le code suivant :

if ( variable1 === 'valeur 1' ) {
//alors
} else if ( variable1 === 'valeur 2' ) {
//sinon si
}
else{
//sinon
}

est l’équivalent de celui-ci :

if ( variable1 === 'valeur 1' ) {
//alors
} else {
if ( variable1 === 'valeur 2' ) {
//sinon si
}
else{
//sinon
}
}

Voici un petit graphe qui compare la vitesse d’exécution de cette structure afin de faire une simple affectation.
Cette structure contient 1 if, 4 elseif et 1 else, chaque niveau correspond à un if/else différent (level 0=if, level 5=else).

Et là grande surprise, remarquez comme la dernière version de firefox, l’air de rien, arrive en tête de se classement ! Firefox n’étant pourtant pas réputé pour son moteur de javascript très performant, il arrive a se démarquer des autres sur les tests conditionnels/affectation de façon impressionnante. Safari 5 en version PC est quant à lui, un peu à la traîne, je rajouterai bientôt le même comparatif en utilisant les navigateurs sous OS X. Opera qui a également amélioré son moteur javascript, se trouve dans la même unité de grandeur que les autres avec un peu d’avance par rapport à Chrome. J’ai été déçu par les résultats de ce dernier sur ce test. Finalement Internet Explorer 9, pourtant prometteur (voir mon autre test) ne se met pas non plus en avant sur ce test.

If Ternaire

Beaucoup de gens l’utilisent également, il est très pratique et surtout lisible quand il s’agit de faire un choix entre deux valeurs en inline. Il marchera même en plein milieu d’une chaîne de caractère ou d’une instruction.

var nb=5,
	s='Il y a '+nb+' utilisateur'+((nb>1)?'s':'')+' sur ce site'; //ici 5 est supérieur à 2, nous aurons donc un S à la fin de utilisateurs

Bon pas trop mal n’est-ce pas, mais ça devient très vite imbuvable et illisible si on veut faire un peu plus compliqué :

var nb=5,
	s='il y a '+((nb>1)?nb+' utilisateurs':((nb>0)?1:'aucun')+' utilisateur')+' sur ce site';

Au niveau du petit combat entre navigateur :

Graphique de comparaison d'un If ternaire sur les navigateurs PC

Toujours firefox de loin en tête, pas de majeurs changement par rapport au test précédent.

If Implicite

Alors là, nous allons un peu jouer avec les spécificités du langage Javascript. Cette structure conditionnelle est très peu utilisée, un peu moins lisible que le if explicite ou ternaire dans certains cas, mais beaucoup plus rapide à écrire et à lire dans d’autres.

Imaginons que nous avons un objet appelé « O », et que nous voudrions appeler la fonction « f » de cet objet seulement dans le cas où cette fonction existe, ainsi avec un if explicite nous ferions :

if(O.f)
	O.f();

Maintenant en if implicite :

O.f && O.f();

Bon on ne gagne pas grand chose ici n’est-ce pas ?

Imaginons une petite fonction getter/setter pour des inputs :

function iV(idt,v){
	var el=document.getElementById(idt) || {};
	el= (el.value && el) || {value:''};
	return el.value =  (arguments>1 && v) || el.value;
}

Ce code est un exemple extrême peu optimisé, mais qui donne un bon aperçu de la syntaxe.
Que fait le code ?
ligne 2 : on récupère notre input et s’il n’existe pas, on retourne simplement un objet vierge pour ne pas générer une erreur javascript ensuite.
ligne 3 : si notre objet contient un champs value, c’est bon, donc on retourne notre objet, sinon, on retourne un objet vierge contenant un champs value pour ne pas non plus générer une erreur javascript ensuite.
ligne 4 : si nous avons plus d’un argument, alors nous affectons notre deuxième argument (v) au champs value de notre input, sinon, on ne change rien, on le réaffecte lui-même. Finalement on retourne tout ça !

Pourquoi ne pas directement à la ligne 3 passer la « value » dans une variable ?
Tout simplement car la « value » n’est pas un objet, et ici ce ne sera pas le pointeur qui sera copié, mais la valeur. Il ne faut pas oublier qu’en javascript les objets sont passé par référence et String/int/Bool/… sont passé par valeur.

Nous enregistrons également notre élément dans une variable el, car document.getElementById prend du temps à s’exécuter, étant donné qu’elle parcourt le Dom de notre page. Ainsi on ne l’appelle ici qu’une seule fois.

Un code équivalent avec une structure if/else :

function iV(idt,v){
	var el;

	if(el=document.getElementById(idt)){
		if(arguments.length>1){
			if(el.value){
				return el.value=v;
			}
			else
				return v;
		}
		else if(el.value)
			return el.value;
	}
	else if(arguments.length>1)
		return v;
	return false;
}

Si on traduit ligne à ligne en structure conditionnelle implicite :

function iV(idt,v){
    var el;
    return (
        (el=document.getElementById(idt)) && (
            (
                arguments.length>1 && (
                    (el.value && (el.value=v))
                    || v
                )
            )
            || el.value
        )
    )
    || (arguments.length>1 && v)
    || false;
}

En réduisant :

function iV(idt,v){
    var el;
    return ((el=document.getElementById(idt)) && ((arguments.length>1 && ( (el.value && (el.value=v)) || v)) || el.value)) || (arguments.length>1 && v) || false;
}

Maintenant les deux codes compressés :

function iV(a,v){var b;if(b=document.getElementById(a)){if(arguments.length >1){if(b.value){return b.value=v}else return v}else if(b.value)return b.value} else if(arguments.length>1)return v;return false}

et

function iV(a,v){var b;return((b=document.getElementById(a))&&((arguments .length>1&&((b.value&&(b.value=v))||v))||b.value))|| (arguments.length>1&&v)||false}

Et on se retrouve avec un code à 156 caractères en if implicite et un à 202 caractères en if explicite, soit 25% de moins ce qui est énorme.

Je pense notamment à ce concours : 10K Apart dont le but était de faire une application web impressionnante, dont la taille serait la plus petite possible, avec une limite de 10kb. Avec cette méthode, j’ai réussi à rapporter le code du gagnant de 6,9kb à 4,1kb. Plutôt sympas non ? pour perdre son temps :P !

Vous l’aurez donc compris, ce code est très utile pour des structures très simple, tel que pour vérifier l’existence d’attributs d’objets, mais très dur à lire dès qu’on arrive dans des structures complexes (et sans habitude ;) ). Toutefois, nous nous rapprochons d’un langage plus brut, et il est donc plus petit au final. Je pense notamment au

Voici pour le petit graphique :

Graphique de comparaison d'un If Implicite sur les navigateurs PC

Ici encore nous tombons sur des résultats sensiblement pareils. Ce qui va être intéressant maintenant, c’est au sein d’un navigateur, quel if est le plus rapide ? C’est l’objet de la partie suivante.

Comparaison des « If »

Voici les comparaisons des trois If par navigateur, les graphiques suffisent à eux-même.

Benchmark if sous Firefox 3.6 PC

Benchmark if sous Internet Explorer 9

Benchmark if sous Opera 10.62

Benchmark if sous Safari 5 PC

Benchmark if sous Chrome 6 PC

Ainsi nous pouvons voir, qu’il faudra privilégier les If Implicites aux If Ternaires qui sont fortement moins performants sur la plupart des navigateurs.
Il est ici impossible de tenir compte de Firefox étant donné l’ordre de grandeur 10 fois moindre, les différences entre les trois if ne sont donc, sur ce navigateur, pas représentatives.

Ce qu’il faut retenir

  • En règle générale, utiliser des if explicites (lisibilité, performance, au détriment du poids)
  • Utiliser des If implicites en lieu et place des If ternaires moins performants (performance)
  • Utiliser des If implicites pour une simple vérification de valeur et une action ou une autre (lisibilité, performance, nombre de caractère plus petit)
  • Pour les grandes structures conditionnelles : utiliser des If Explicites à moins de vouloir à tout pris gagner des kilo-octets sur le poids du fichier script (lisibilité)

A bientôt !

(PS: je n’ai pas corrompu les résultats de Firefox, mon navigateur favori étant Safari)

Share and Enjoy:
  • Google Bookmarks
  • Facebook
  • del.icio.us
  • Digg
  • Live

One Response to “Javascript et les trois manières de faire un IF”

Leave a Reply