Dans la plupart des langages, les chaînes de caractères ne sont pas modifiables. Ajouter un caractère à une chaîne existante c’est créer un nouvel objet avec la chaîne résultante. Parfois comme dans ruby ce n’est pas visible pour l’utilisateur mais c’est bien ce qui est fait en interne. pour éviter que de multiples concaténations ne posent des problèmes de performance, on a souvent à disposition un objet spécifique StringBuffer dédié à cet usage. Ce n’est malheureusement pas le cas en javascript et on voit passer de nombreuses recommandations de micro-optimisation pour compenser.
Tom Trenka a voulu faire le point en juin. Il a comparé différentes méthodes pour concaténer des chaînes de caractères et l’implémentation StringBuffer de Dojo. L’analyse est assez poussée et remet quelques préjugés courants sur le tapis.
Je vous recommande vraiment la lecture du billet en anglais donc je ne ferai que mes conclusions :
Opérations sur un tableau de chaînes de caractères
Rien de révolutionnaire finalement. La première conclusion c’est que faire une seule opération de concaténation est toujours plus rapide que de faire de multiples opérations unitaires dans une boucle. Le navigateur peut créer directement la chaîne résultante à la bonne taille sans passer par plein de résultats intermédiaires.
Si vous avez un tableau de chaînes de caractères vous avez le choix entre join()
et concat()
. Le premier est un petit peu lent sur Firefox 2, le second est très lent sur Microsoft Internet Explorer 7.
Bref, si vous avez déjà un tableau de chaînes de caractères, utilisez join()
pour réaliser la concaténation.
Itérations multiples
C’est ici que le premier préjugé tombe. Trop de gens conseillent d’instancier un tableau puis d’envoyer un à un les fragments dans ce tableau pour faire un join()
à la fin. Et bien… non : une boucle avec des concaténations à base de +=
est plus rapide, pour tous les navigateurs récents. Tom Trenka a refait le test pour MSIE 6, mais si dans ce cas join()
est plus rapide, la différence n’est pas suffisament importante pour qu’il soit une bonne idée de ralentir tous les autres navigateurs ou de faire deux versions de votre bibliothèque. De manière générale, +=
est probablement une meilleure option pour concaténer une chaîne dans uen boucle.
C’est tout de même à modérer suivant les conditions. En particulier sur des itérations importantes (>1000) ou des données de très grande taille (> 5000 mots) alors join()
redevient utile. C’est particulièrement vrai pour MSIE si les données approchent les 64ko. Cependant personnellement je dois faire assez rarement des concaténations avec 1000 itérations ou des données de plus de quelques kilo-octets. Faites vos propres tests si vous avez des doutes.
Quelques optimisations
Une dernière recommandation peut toutefois sortir des deux analyses de Tom : préférez faire vos concaténations sur des petites chaînes de caractères. Si vous construisez une grosse chaîne HTML, XML ou JSON, faites vos concaténations sur une variable temporaire puis ajoutez là à votre grosse donnée au dernier moment.
Il y a d’autres remarques intéressantes mais qui ne concernent pas spécifiquement la concaténation, je vous les réserve pour plus tard.
La dernière partie (« Quelques optimisations ») est particulièrement intéressante. Je n’aurais pas pensé que plusieurs concaténations successives de petites choses puis concaténer le résultat à une grosse donnée auraient été plus performant que de tout concaténer à la grosse donnée directement.
Bon à savoir !