web-dev-qa-db-fra.com

Pourquoi JavaScript n'est-il pas compilé en bytecode avant d'envoyer sur le réseau?

Vous verriez souvent que JavaScript est en fait transporté sur le Web avec toutes les choses inutiles qui n'ont pas besoin d'être là - Commentaires, en particulier ceux contenant des licences, indentations ( '\ t' , '\ n' ), etc. Avec suffisamment de temps, cela pourrait finir par gaspiller des téraoctets de données dans le monde entier! Un bytecode JavaScript causerait-il un autre problème plus important, ou personne n'y a encore pensé?

155
Vivek Yadav

Pourquoi JavaScript n'est-il pas compilé en bytecode avant d'envoyer sur le réseau?

Contexte: Je faisais partie du comité technique ECMAScript à la fin des années 1990 et l'un des implémenteurs du moteur JScript de Microsoft.

Permettez-moi de commencer par dire ce que je dis toujours face à un "pourquoi pas?" question: les concepteurs de langage ne sont pas tenus de donner de bonnes raisons pour lesquelles ils n'ont pas dépensé des centaines de millions de dollars d'autres personnes pour une fonctionnalité que quelqu'un aime. Au lieu de cela, la personne qui lance la fonctionnalité doit donner de bonnes raisons pour lesquelles c'est la meilleure façon de dépenser ce temps, ces efforts et cet argent. Vous avez fait valoir sans aucun chiffre attaché que le bytecode serait une économie en termes de bande passante. Je vous encourage à trouver des chiffres réels et à les comparer aux coûts de création d'une autre langue; ces coûts sont importants. N'oubliez pas dans votre analyse que la "mise en œuvre" est l'un des plus petits coûts. Dans votre analyse, incluez également qui économise l'argent par rapport à qui dépense l'argent , et vous constaterez que les gens qui dépensent l'argent ne sont pas ceux qui le sauvent; les incitations comptent.

Cela dit, c'est l'un des "pourquoi pas?" Les plus raisonnables. questions parce que c'est une fonctionnalité que nous avons considérée et rejetée pour des raisons.

Nous avons envisagé un tel schéma, à la fois au sein de Microsoft et au niveau de TC; étant donné que JScript a déjà été implémenté en tant que compilation dans un langage de bytecode bien conçu et basé sur des principes, il aurait été simple pour nous de le proposer comme standard et nous avons envisagé de le faire.

Nous avons décidé de ne pas le faire, pour diverses raisons, notamment:

  • Dieu merci, il était déjà assez difficile de standardiser JavaScript . Tout le monde et leur chien auraient une opinion sur les caractéristiques idéales d'un langage de bytecode, et ce serait plusieurs années de bikeshedding. Personne ne voulait vraiment y aller.
  • C'était une solution coûteuse sans problème coûteux associé. Il n'y a aucune raison de supposer qu'un langage de bytecode serait plus efficace en taille ou en vitesse. JavaScript minimise déjà assez bien et est très compressible.
  • Cela aurait créé une énorme quantité de travail pour les fournisseurs de navigateurs, qui étaient déjà contrariés par les coûts de production d'une implémentation JS efficace et conforme.
  • La création d'une implémentation JS sécurisée qui résiste aux attaques de mauvais acteurs est déjà assez difficile; faut-il doubler la surface disponible pour attaquer? Probablement pas.
  • Les normes sont un obstacle à l'innovation. Si nous découvrions qu'un petit changement à notre langage de bytecode ferait une grande différence dans certains imprévus ou peu importants auparavant scénario utilisateur, nous étions libres de faire ce changement. S'il s'agissait d'une norme, nous ne serions pas libres de créer cet avantage pour l'utilisateur.

Mais cette analyse suppose que la raison de faire cette fonctionnalité est la performance. Chose intéressante, les demandes des clients qui ont motivé la prise en compte de cette fonctionnalité dans les années 1990 n'étaient pas principalement liées aux performances.

Pourquoi pas? Les années 1990 ont été pour JS une période très différente de celle d'aujourd'hui; les scripts étaient pour la plupart minuscules. L'idée qu'il y aurait un jour des cadres avec des centaines de milliers de lignes n'était même pas près d'être sur notre radar. Le téléchargement et l'analyse de JS représentaient une infime fraction du temps consacré au téléchargement et à l'analyse de HTML.

La motivation n'était pas non plus l'extension à d'autres langues, même si cela intéressait Microsoft, car nous avions également VBScript en cours d'exécution dans le navigateur, qui utilisait un langage de bytecode très similaire. (Développé par la même équipe et compilé à partir des mêmes sources et de tous.)

Au contraire, le principal scénario client pour motiver le bytecode dans le navigateur était de rendre le code plus difficile à lire, à comprendre, à décompiler, à rétroconcevoir et à falsifier. Le fait qu'un langage de bytecode ne soit guère un travail supplémentaire à comprendre pour tout attaquant disposant de ressources raisonnables était un argument majeur contre ce travail; nous ne voulions pas créer un faux sentiment de sécurité.

Fondamentalement, il y avait beaucoup de dépenses et quelques avantages précieux, donc cela n'a pas été fait. Quelque chose a dû changer entre 1998 et 2015 qui a fait que WebAssembly a un rapport prix/avantages raisonnable; quels sont ces facteurs, je ne sais pas. Vous devrez demander à un expert sur WebAssembly.

381
Eric Lippert

Voir la source

"View Source" était au début, et est encore dans une certaine mesure, considéré comme une caractéristique importante du Web. C'est ainsi que des générations de développeurs Web ont appris le développement Web, et les organismes de normalisation compétents (ECMA TC39, W3C, WHATWG) le prennent toujours très au sérieux.

Minification

Les fichiers ECMAScript sont généralement "minifiés" avant d'être déployés. Cela inclut la suppression de tous les commentaires, tous les espaces et le changement de nom de tous les identifiants pour qu'ils soient aussi courts que possible, ainsi que certaines optimisations de niveau supérieur telles que la suppression du code mort.

Compression

Le support de la compression existe dans HTTP depuis HTTP/1.0 (début 1996). ECMAScript est du texte et le texte se comprime très bien. En fait, ECMAScript est un texte avec beaucoup de redondances (beaucoup d'apparences de ;, {, }, (, ), ,, ., function, var, if, for, etc.), et les algorithmes de compression reposent sur la redondance. Ainsi, la quantité de données transférées est beaucoup plus petite que vous ne le pensez. À titre expérimental, essayez de compresser un fichier source ECMAScript avec l'un des algorithmes de compression typiques utilisés sur le Web (par exemple gzip ou deflate), et comparez cela à la taille du bytecode compilé du même fichier.

Format de bytecode

Ce qui nous amène au problème suivant: il n'y a pas de format de bytecode standardisé pour ECMAscript. En fait, certaines implémentations peuvent même ne pas utiliser du tout le bytecode! Par exemple, pendant les deux premières années, V8 a compilé ECMAScript directement en code machine natif, sans étape de bytecode entre les deux. Chakra, SquirrelFish Extreme et SpiderMonkey utilisent tous du bytecode, mais ils utilisent un bytecode différent. dyn.js, TruffleJS, Nashorn et Rhine n'utilisent pas de bytecode spécifique à ECMAScript, ils se compilent en bytecode JVML. De même, IronJS compile en bytecode CLI CIL.

Maintenant, vous pourriez dire: pourquoi ne pas définir un format de bytecode standardisé pour ECMAScript? Les problèmes avec ceci sont doubles:

  1. Un format de bytecode contraint la conception du moteur d'exécution. Par exemple, regardez les JVM: les JVM sont beaucoup plus similaires les unes aux autres que les moteurs ECMAScript. Personnellement, je pense que la "course à la performance" de la fin des années 2000/début des années 2010 n'aurait pas été possible sans le large éventail d'expérimentation que l'absence d'un format de bytecode standardisé a permis.

  2. Non seulement il est difficile de faire en sorte que tous les fournisseurs de moteurs ECMAScript se mettent d'accord sur un format de bytecode standardisé commun, mais considérez ceci: cela n'a pas de sens d'ajouter un format de bytecode pour uniquement ECMAScript au navigateur. Si vous faites un format de bytecode commun, ce serait bien s'il supportait ActionScript, VBScript, Python, Ruby, Perl, Lua, PHP, etc. comme bien. Mais maintenant, vous avez le même problème que dans # 1, à l'exception d'une augmentation exponentielle: non seulement tous les fournisseurs de moteurs ECMAScript doivent se mettre d'accord sur un format de bytecode commun, vous devez également obtenir PHP, Perl, Ruby, Python, Lua, etc. les communautés sont également d'accord!

Mise en cache

Les bibliothèques bien connues et largement utilisées sont hébergées sur des URI canoniques, où elles peuvent être référencées à partir de plusieurs sites. Par conséquent, ils n'ont besoin d'être téléchargés qu'une seule fois et peuvent être mis en cache côté client.

CDN

De nombreuses bibliothèques utilisent des CDN, elles sont donc réellement servies à partir d'un emplacement proche de l'utilisateur.

Wasm/asm.js

WebAssembly (Wasm) est un format d'instructions binaires compact qui est actuellement en cours de standardisation par le W3C et déjà livré avec Firefox, Chrome, Safari et Edge. Cependant, il n'est pas conçu comme format de bytecode pour ECMAScript, mais plutôt comme un code machine portable de bas niveau et une cible de compilation pour des langages comme C, C++ et Rust.

Avant Wasm, il y avait déjà asm.js, qui avait des objectifs similaires, mais il était conçu comme un sous-ensemble syntaxique et sémantique d'ECMAScript, vous pouvez donc l'exécuter sans modification dans un moteur non compatible avec asm.js, et cela fonctionnerait, juste beaucoup plus lent.

114
Jörg W Mittag

JavaScript a été inventé par Netscape. L'objectif de conception était de rendre les pages Web interactives via un langage de script intégré. Il n'était pas initialement destiné à une application complexe - des choses complexes étaient censées être écrites comme Java applets ou plug-ins, et JavaScript était positionné comme un simple code "glue" qui pouvait connecter des éléments HTML avec = Java applets et autres plug-ins scriptables.

JavaScript a été conçu pour être intégré directement au HTML, comme <input type="button" onclick="alert('hello world')">. De nos jours, il est mal vu d'incorporer JavaScript dans HTML, mais à l'époque c'était la façon standard de connecter les gestionnaires d'événements. Dans ce cas d'utilisation, JavaScript devait essentiellement être basé sur du texte.

Il y avait aussi des installations pour générer du HTML en JavaScript, comme:

<script>
  document.write("<input type=\"button\" onclick=\"alert('hello world')\">"
</script>

Encore une fois, cela nécessite essentiellement que JavaScript soit au format textuel pour être utile.

De plus, un format textuel est beaucoup plus facile pour les développeurs occasionnels, car vous n'avez pas besoin d'un environnement de développement pour le compiler en bytecode. Il vous suffit de taper le texte et de recharger le navigateur pour le voir s'exécuter. Au moment où JavaScript a été introduit, les éditeurs HTML dédiés existaient à peine. Les gens ont écrit des pages Web dans le bloc-notes. Il n'y avait pas de pipelines de construction pour les pages Web.

Les inconvénients que vous mentionnez n'étaient pas vraiment une considération à l'époque. Puisqu'il était conçu pour de petits scripts, la surcharge d'un format textuel était complètement insignifiante.

18
JacquesB

L'utilisation des données n'est probablement pas réellement un problème.

Pour répondre à l'hypothèse dans le corps (depuis le merveilleux réponse d'Eric Lippert semble avoir assez bien couvert les questions réelles):

Que vous parliez de limites de données ou de bande passante, mon Google-Fu n'a pas été en mesure de dénicher des recherches suggérant que Javascript "gaspille des téraoctets de données" (quoi que cela signifie).

Quant au reste de vos questions, à bien des égards, il est moins utile de se demander "quels problèmes cela causera-t-il?" que de demander d'abord "quels avantages cela créera-t-il?".

1
sp88