IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Pourquoi générer le code JavaScript est une fausse bonne idée.

Le , par sekaijin

0PARTAGES

8  0 
Bonjour.

En lisant le forum et en répondant aux questions, je me suis dit qu'une petite mise au point semblait nécessaire.

Souvent, dans nos développements, nous avons un serveur dynamique PHP, ASP, JAVA, C#, Ruby, etc.

Il est très facile et tentant de générer les divers éléments dont on a besoin directement avec le langage de ce serveur.

C'est simple, ça apporte des facilités mais ce n'est pas toujours aussi efficace qu'on le pense.

Lorsqu'on crée le code HTML de la page, on place au fur et à mesure le code JavaScript dont on a besoin en incluant directement dans celui-ci, tout comme pour le HTML, les valeurs des variables du langage hôte.
Code php : Sélectionner tout
1
2
3
4
5
6
7
<?PHP 
  $Message = '"Hello World!"'; 
  print '<script type="text/javascript">'; 
  print '    function confirm(message) { ..... }'; 
  print '</script>'; 
  print "<a href='#' onClick = 'return confirm(".$Message.");'>Test</a>"; 
?>

Parmi les avantages, le regroupement de tout le code concernant un point précis. Ici la confirmation du message.
Dans le langage hôte, nous avons la définition de la valeur,
la génération du code JavaScript qui l'utilise
et le code HTML qui permettra de l'invoquer.

Autre avantage, on peut très facilement ne produire que le code JavaScript nécessaire à ce besoin. Si la fonction JavaScript à utiliser dépend d'une propriété dans le langage hôte, un simple if permet de produire la bonne fonction.

Bref, je ne vais pas énumérer les avantages et encore moins les inconvénients.

Mon propos est juste de montrer pourquoi cette idée est une fausse bonne idée.
Pour cela revenons, au fonctionnement du Web, c'est-à-dire HTTP.

  1. Le client invoque une URL.
  2. Le serveur déroule son code et produit dynamiquement une source HTML.
  3. Le client reçoit cette source.
    • Il ne peut pas le mettre en cache car il est dynamique et contient des données variables.
    • Il le parse et crée le DOM correspondant.
    • Il donne à l'interpréteur JavaScript la source JavaScript qu'il contient.
  4. L'interpréteur JavaScript compile le code (partiellement) et le relie au DOM.
    • L'interpréteur ne peut mettre le code compilé en cache car il est embarqué dans une source qui n'est pas cachée.
  5. La page est disponible pour l'utilisateur.
  6. L'utilisateur active le code JavaScript par une action (un click dans l'exemple).
  7. L'interpréteur JavaScript compile si besoin le code non compilé et l'exécute.
    • Si l'action est encore invoquée, elle est juste exécutée.

Si le client au cours de son activité revient sur la même page, on repart du début.
Le code est régénéré, retransféré, réinterprété par le moteur HTML, recompilé pour le JavaScript et ce à chaque fois qu'on invoque l’URL.

Peut-on gagner en efficacité ? La réponse est oui évidemment, en utilisant le protocole et la capacité du navigateur.

La première chose à faire est de mettre le code JavaScript dans des fichiers séparés
Code javascript : Sélectionner tout
function confirm(message) { ..... }
et inclure le fichier dans la page.

Reste l'utilisation des variables du langage hôte dans JavaScript.
J'ai donné une solution ici, avec celle-ci il n'est plus du tout nécessaire de placer les valeurs des variables du langage hôte dans JavaScript.

En quoi une telle solution peut-elle améliorer l'efficacité ?
Reprenons le déroulement des opérations.

  1. Le client invoque une URL
  2. Le serveur déroule son code et produit dynamiquement une source HTML.
  3. Le client reçoit cette source.
    • Il ne peut pas la mettre en cache car elle est dynamique et contient des données variables.
    • Il la parse et crée le DOM correspondant.
    • Il charge les fichiers JavaScript liés.
    • Il met la source JavaScript dans le cache.
  4. L'interpréteur JavaScript compile le code (partiellement) et le relie au DOM.
    • L'interpréteur met en cache le code compilé.
  5. La page est disponible pour l'utilisateur.
  6. L'utilisateur active le code JavaScript par une action (un clic dans l'exemple).
  7. L'interpréteur JavaScript compile si besoin le code non compilé et l'exécute.
    • Si l'action est encore invoquée elle est juste exécutée.


Si la page est rappelée, le fichier JavaScript n'est pas rechargé et il n'est pas recompilé.

Du coup diront certains, on se retrouve avec un gros JavaScript qui contient tout les cas alors qu'en générant le JavaScript à la volée, je peux générer la fonction dont j'ai besoin
Code php : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
<?PHP 
  $Message = '"Hello World!"'; 
  print '<script type="text/javascript">'; 
  print '    function confirm(message) {'; 
  if ($property == 'some value' { 
     print "       //ici le code JavaScript dans un cas"; 
  } else { 
     print "       //ici le code JavaScript dans l'autre cas"; 
  } 
  print '    }'; 
  print '</script>'; 
  print "<a href='#' onClick = 'return confirm(".$Message.");'>Test</a>"; 
?>

C'est en fait un faux problème. Il suffit de faire plusieurs fichiers JavaScript et d'inclure le bon.
Code php : Sélectionner tout
1
2
3
4
5
6
<?PHP 
  $Message = '"Hello World!"'; 
  print '<script type="text/javascript" src="' . $property . '.js">'; 
  print '</script>'; 
  print "<a href='#' onClick = 'return confirm" . $property . "(".$Message.");'>Test</a>"; 
?>

On a ainsi le code précis de la fonction que l'on veut dans le JavaScript tout en bénéficiant du cache du compilateur JavaScript et du cache du navigateur.

Cet aspect des choses peut avoir de gros effets.
Sur de tout petits JavaScript, ça ne se voit quasiment pas.
Mais ce n'est pas le cas lorsqu'ils se multiplient ou si le code devient plus gros.

Ajoutez les caches réseaux dans l'affaire et la différence peut devenir énorme.

Vous avez sûrement remarqué que certaines applications sur le net sont très lentes à démarrer la première fois et bien plus rapides par la suite.

Imaginez une telle application dont le serveur est à l'autre bout du monde. Tout le code statique, CSS statique, images statiques est mis en cache dans des caches réseau tout au long du parcours (le proxy de l'entreprise fait aussi cela).

Du coup, lorsqu'un autre client vient chercher une de ces ressource et que le réseau la trouve en cache dans l'acheminement de la requête, c'est cette version en cache qui est livrée. Ce n'est donc plus simplement juste entre le client et le serveur qu'on optimise ainsi les transferts mais sur toute la ligne.

Avec JavaScript, il y a en plus le cache du code compilé qui apporte un réel confort à l'utilisateur. L'application devient beaucoup plus fluide et réactive.

A+JYT

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de sekaijin
Expert éminent https://www.developpez.com
Le 16/11/2011 à 16:36
petite précision sur ressource statique et ressource dynamique

ce sont les headers de la réponse qui permettent au navigateur de décider si c'est statique ou dynamique.

un fichier sur le serveur servit par http est par défaut statique.
(à moins que httpd soit configuré différemment)

un serveur dynamique php java etc.
produit lui par défaut des ressources dynamiques. (l'entête est par défaut pas de cache)

mais comme ils sont programmable le développeur peut choisir de rendre une ressource produite dynamiquement, statique en positionnant les headers de la réponse.

dans ce dernier cas le client considère la ressource comme statique.

on peut se poser la question lorsqu'il s'agit d'une ressource javascript du pourquoi générer avec un serveur dynamique un js statique.

généralement lorsqu'on produit dynamiquement une ressource c'est justement parce son contenu risque de changer régulièrement.
si on position les headers pour la rendre statique (vu du client) ce contenu ne sera pas rechargé du coup pourquoi la produire dynamiquement ?

il y a là une espèce de contradiction.

il arrive que l'on produise des ressources dynamiquement mais celles-ci changeant très peu on positionne le header pour les montrer comme statique. c'est le cas des blog par exemple. la page d'un article ne change pas à chaque appel.

mais pour du javascript ?
soit le code change souvent. (je ne connais pas de cas typique)

soit il ne change pas du tout. ce qui change ce sont les données.
mieux vaut donc générer les ressources pour les données dynamiquement et le code statiquement.

A+JYT
1  0 
Avatar de Benjamin Delespierre
Expert éminent https://www.developpez.com
Le 25/01/2012 à 17:21
On peut d'ailleurs ajouter qu'il est possible d'envoyer des headers 304 pour faire comprendre au navigateur qu'une ressource pourtant générée dynamiquement pas PHP n'a pas évolué. On se sert pour cela du Last-Modified et du etag envoyés par le navigateur pour identifier la ressource mise en cache.

Les explications sont disponibles ici: http://alexandre.alapetite.fr/doc-al.../php-http-304/

On peut donc toujours faire générer ce qu'on veut par PHP et conserver le bénéfice du cache du navigateur. Ce qui est terriblement pratique dans le cadre d'émission de flux RSS.

Cela étant, je ne remets pas en cause la pertinence de cet article, je suis de ceux qui pensent que le JavaScript et le CSS ne doivent pas être générés dynamiquement. Je tenais juste à ajouter mon grain de sel
1  0 
Avatar de Bovino
Rédacteur https://www.developpez.com
Le 10/11/2011 à 21:08
Merci pour cette analyse particulièrement intéressante !
0  0 
Avatar de Lcf.vs
Membre éclairé https://www.developpez.com
Le 11/11/2011 à 18:39
Ne serait-ce pas pas mieux d'orienter vers une solution de génération, à la volée, en DOM PHP? (avec un cache PHP, bien entendu)

'fin, c'est ce que je fais...
0  0 
Avatar de sekaijin
Expert éminent https://www.developpez.com
Le 11/11/2011 à 21:22
non car le cache php est côté serveur le client devra donc toujours recompiler le code js.

De plus pas de cache réseau dans ce cas.

encore une fois mon propos est de sensibiliser.

mieux vaut faire ses choix en connaissance de cause.

A+JYT
0  0 
Avatar de Lcf.vs
Membre éclairé https://www.developpez.com
Le 11/11/2011 à 21:31
Si le fichier servi depuis le cache de PHP est toujours le même qu'à la visite précédente, pourquoi serait rechargé et recompilé, côté client?

La source étant la même (domaine, url, fichier, etc.), le navigateur doit aller le rechercher en cache, non?
0  0 
Avatar de sekaijin
Expert éminent https://www.developpez.com
Le 11/11/2011 à 21:58
Si la page est dynamique le navigateur ne la mets pas en cache car sinon il ne pourrait avoir la bonne version à chaque appel.

ne la mettant pas en cache il doit réinterprété la rechargé.
ensuite (en cache ou pas) le navigateur interprète le code HTML de la page. et si celle-ci contient du js le js est compilé.

si le script est statique et lié à la page
le navigateur met en cache le script lorsqu'il interprète le HTML.
puis il le compile et mets la version compilé en cache.

à l'appel suivant que la page soit dynamique ou pas il réinterprète le HTML mais va cherché le JS déjà compilé dans le cache.

agir côté serveur ne change donc rien.

mais l'un n'empêche pas l'autre. lorsqu'on travail à la fluidité de son application il faut agir à tout les niveaux.

lorsque l'application est complexe et qu'il y a beaucoup d'éléments à échanger. il faut penser aux caches serveur (php) aux caches statiques des frontaux (java) aux caches réseau et proxies, au cache fichier du navigateur, au cache du compilateur js.

généré du js à la volé peut être intéressant. Mais parfois ça peut aussi être contre productif.

imagine que dans deux cas une fonction foo fasse deux chose différente. pour simplifier la vie et en pensant qu'ainsi tu ne produit que js dont tu a besoin tu décide de produire le code de foo à la volé.
à chaque appel foo ne contient que le code nécessaire.

foo étant un fonction complexe tu préfère ça à deux fonction foo1 et foo2 te disant qu'ainsi tu ne vas pas charger coté navigateur deux grosse fonction.

tout ce discours semble cohérent et montrer que c'est optimal.

en fait ton client va chargé à chaque fois un des deux code foo le compiler et l'interpréter.

si tu avais fais deux fonction foo1 et foo2 statiques effectivement le premier chargement serait plus lourd tout comme la compilation. mais ensuite ton client ne fait qu'utiliser ce qu'il a déjà.

il est évident que suivant la taille du code et le nombre de fois ou il est utilisé
les avantage d'une solution ou de l'autre changent.

pour une fonction utilisé une fois ça ne change rien.
pour une grosse fonction ou un grand nombre de petites fonctions utilisée des centaines de fois ça change tout.

dans la vrais vie on est quelque part entre les deux et il n'est pas évident de percevoir l'impact.

pour finir
lorsqu'on génère un contenus dynamiquement mais avec les headers qui permettent la mise en cache. pour le client c'est comme une ressource statique. le client ne la redemandera pas. (on utilise souvent cela en java) mais dans ce cas le contenus de la ressource n'est pas dynamique.

A+JYT
0  0 
Avatar de armelbd
Nouveau Candidat au Club https://www.developpez.com
Le 14/11/2011 à 9:39
Il y a quelque chose que j'ai du mal à comprendre, comment le client distingue une ressource dynamique d'une ressource statique ?
0  0 
Avatar de sekaijin
Expert éminent https://www.developpez.com
Le 14/11/2011 à 20:28
dans l'entête de la réponse
0  0 
Avatar de beegees
Membre expérimenté https://www.developpez.com
Le 15/11/2011 à 19:58
Merci, très intéressant ton article.
0  0