JavaScript revient de loin. A l'origine il n'était qu'une source d'incompatibilités et un véritable cauchemar pour les designers web. Devoir coder une version IE et une version Netscape d'un même site web était monnaie courante. Heureusement, le langage JavaScript a incroyablement évolué pour devenir le compagnon omniprésent de HTML5 sur presque tous les sites internet de la planète. Avec la dernière version du langage, adoptée comme nouveau standard cet été, de nouvelles possibilités sont apparues, qui méritent d'être connues et exploitées.
Différentes versions
Inventé en 1996 chez Netscape, JavaScript n'a été raisonnablement standardisé qu'en 2000 à partir de la version 1.5, sous le nom EcmaScript revision 3 (ES3). Durant 15 ans, presque rien de nouveau n'a réellement été standardisé, et c'est les éditeurs des navigateurs qui ont fait avancer le langage à leur façon, heureusement de manière un peu moins désorganisée qu'avant 2000.
Une variante du langage appelée node.js est apparue vers 2010, permettant l'utilisation de JavaScript hors du navigateur. Le moteur et les constructions du langage sont les mêmes, mais la librairie de classes est différente, ce qui complique la portabilité d'un environnement à l'autre.
Le nouveau standard EcmaScript revision 6 s'appelle officiellement EcmaScript 2015, et c'est lui qui nous intéresse aujourd'hui. Il n'est pas encore entièrement implémenté dans tous les navigateurs, mais il existe des outils permettant de l'utiliser dès maintenant.
Quoi de neuf ?
Voyons ce qui peut nous intéresser dans cette nouvelle version, en particulier pour l'utilisation des modules Yoctopuce.
Gestion de la concurrence
Chaque langage de programmation doit apporter une solution à la gestion de la concurrence entre les différentes tâches. JavaScript propose un modèle assez particulier, qui consiste à n'utiliser qu'un seul thread et à passer le contrôle d'une tâche à l'autre par le moyen de callbacks. Le système est totalement non-préemptif, ce qui signifie qu'une tâche ne peut reprendre le contrôle que lorsqu'aucune autre ne s'exécute et qu'une opération asynchrone se termine. C'est une technique très performante, mais très malpratique à utiliser car elle exige que chaque tâche rende constamment la main pour permettre aux autres tâches d'avancer.
EcmaScript 2015 apporte des outils qui permettent de rendre la main et de reprendre ultérieurement l'exécution au même endroit, ce qui n'était pas possible précédemment. C'est très intéressant pour nous, car l'utilisation de requêtes bloquantes vers nos capteurs pouvait
poser problème dans certains cas.
Classes et héritage
EcmaScript 3 utilisait un modèle d'objet un peu primitif basé sur des structures contenant des fonctions et des prototypes. La version 2015 ajoute une vraie syntaxe pour déclarer des classes, introduit l'héritage et corrige le problème du this qui ne se comportait parfois pas comme on s'y attendait dans les fonctions définies à l'intérieur d'un objet.
Librairie
Plusieurs classes introduites durant les dernières années par les navigateurs ont été standardisées. Cela nous intéresse en particulier pour la gestion des objets binaires (tableaux de bytes), pour lesquels il n'y avait pas de solution standard.
Un example
Nous préparons en ce moment une nouvelle librairie pour EcmaScript, qui sera utilisable aussi bien dans les navigateurs qu'avec Node.JS. Pour illustrer son utilisation, voici un des exemple classique qui sert à lister les modules Yoctopuce connectés. Première version, sous Node.JS:
async function startDemo()
{
let errmsg = new YErrorMsg();
await YAPI.DisableExceptions();
// Setup the API to use the VirtualHub on local machine
if(await YAPI.RegisterHub('http://127.0.0.1:4444/',errmsg) != YAPI.SUCCESS) {
console.log('Cannot contact VirtualHub on 127.0.0.1');
}
refresh();
}
async function refresh()
{
let errmsg = new YErrorMsg();
await YAPI.UpdateDeviceList(errmsg);
let module = YModule.FirstModule();
while(module) {
let line = await module.get_serialNumber();
line += '(' + (await module.get_productName()) + ')';
console.log(line);
module = module.nextModule();
}
setTimeout(refresh, 500);
}
startDemo();
Si vous connaissez notre API, vous remarquerez que cela ressemble à n'importe quel langage "normal", avec comme seule différence les mots-clé async et await, qui servent à gérer la concurrence. Voilà qui est beaucoup plus lisible que les cascades de callback que nous aurions du utiliser sinon...
Notez que async et await ne font pas strictement partie du standard EcmaScript 2015, ils font partie de la version suivante en préparation. Mais comme les outils EcmaScript 2015 permettent déjà de les utiliser, nous en profiterons vu l'intérêt qu'ils représentent pour nous.
Voici la même chose, pour une interface HTML destinée à un navigateur. Voici d'abord le contenu de inventory.js:
async function startDemo()
{
let errmsg = new YErrorMsg();
await YAPI.DisableExceptions();
// Setup the API to use the VirtualHub on local machine
if(await YAPI.RegisterHub('http://127.0.0.1:4444/', errmsg) != YAPI.SUCCESS) {
alert('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
}
refresh();
}
async function refresh()
{
let errmsg = new YErrorMsg();
await YAPI.UpdateDeviceList(errmsg);
let html = '';
let module = YModule.FirstModule();
while(module) {
html += await module.get_serialNumber();
html += '(' + (await module.get_productName()) + ')<br>';
module = module.nextModule();
}
document.getElementById('list').innerHTML = html;
setTimeout(refresh, 500);
}
startDemo();
Et le code HTML qui va avec:
<html>
<head>
<title>Modules inventory</title>
<script src='../../jspm_packages/system.js'></script>
<script src='../../config.js'></script>
<script>
System.import('example_html/Doc-Inventory/inventory');
</script>
</head>
<body>
<h1>Device list</h1>
<span id='list'></span>
</body>
</html>
L'inclusion de system.js et config.js sert à charger dans le navigateur le gestionnaire de modules ES6 (appelé SystemJS). Lorsque l'on passe le code en production, on peut automatiquement générer un fichier JavaScript unique qui remplacera tous les includes indépendants par un unique appel, comme ceci:
<html>
<head>
<title>Modules inventory</title>
<script src='inventory-sfx.js'></script>
</head>
<body>
<h1>Device list</h1>
<span id='list'></span>
</body>
</html>
Utiliser EcmaScript 2015 en... 2015
Les navigateurs ne sont pas encore entièrement prêts pour cette nouvelle version de EcmaScript. Mais vu son grand intérêt, des outils ont été développés pour permettre son utilisation dès aujourd'hui. Nous prendrons donc
- un transpiler, qui transformera le code EcmaScript 2015 en code EcmaScript 3
- quelques shims, qui sont les morceaux de librairies manquants
- un gestionnaire de modules pour gérer le chargement et les dépendances
Après une longue revue de la jungle des outils JavaScript, nous avons opté pour Babel et jspm, qui sont parfaitement intégrés et sont très complets.
Après une longue revue de la jungle des outils JavaScript, nous avons opté pour Babel et jspm, qui sont parfaitement intégrés et sont très complets.
Comme éditeur, nous utilisons WebStorm, qui est capable d'effectuer au vol une vérification syntaxique et sémantique pour EcmaScript 2015, et qui vaut le prix auquel il est vendu.
Voici des instructions pas-à-pas pour installer et utiliser ces outils:
Installation
Commencez par installer Node.Js pour votre système, car vous en avez besoin pour installer jspm. C'est très facile, sous Windows il n'y a même qu'à lancer l'installeur et c'est fait. Choisissez bien de l'installez en entier, y compris npm, et de l'ajouter au path du système.
Ensuite, il faut installer jspm sur la machine. Cela se fait très simplement à l'aide d'une commande npm:
Il ne reste plus qu'à préparer npm et jspm à travailler avec notre librairie Yoctopuce pour EcmaScript. Pour cela, on se met dans le répertoire racine de la librairie et on lance:
jspm install
Lancement des exemples de la librairie
Pour transpiler et lancer avec Node.JS un des exemples, il suffit d'utiliser la commande jspm run:
Pour les examples HTML, c'est encore plus simple: il suffit d'ouvrir le fichier HTML avec un navigateur, puisque c'est le gestionnaire de module SystemJS qui chargera et transpilera au vol le code.
Pour éviter de transpiler la librairie à chaque exécution, car cela prend quelques secondes, on peut demander à jspm de pré-construire un paquet (appelé bundle) avec la traduction de toutes les classes et tous les shims nécessaires à exécuter ces classes. Voici comment faire:
Le gestionnaire de module sera alors capable d'intercepter automatiquement toutes les références au module yocto_api et à utiliser le bundle pré-transpilé à la place.
Finalement, pour faire un fichier monolithique compressé avec toutes les dépendances d'un projet, comme indiqué plus haut, on utilise la commande suivante:
Disponibilité
Nous devons encore tester cette nouvelle librairie, convertir tous les exemples et adapter la documentation avant de pouvoir la publier. Il faudra donc patienter encore quelques semaines pour en avoir une version officielle. Mais si vous êtes intéressé à faire du Beta-test, ou simplement à nous donner votre avis sur les choix que nous avons fait, n'hésitez pas à nous contacter par mail !