Après plus d'un an de gestation sur GitHub, le projet Streams vient d'être adopté par le WHATWG dans un effort de standardisation d'une API de streaming web. Ce projet est mené par Domenic Denicola, qui est aussi à l'origine du travail sur les promesses qui fait actuellement partie d'ECMAScript 6.
Le but de l'API est de mettre à disposition des primitives I/O de bas niveau pour "créer, composer et consommer des flux de données". Ils sont destinés à être des flux bruts pour la fabrication d'API plus haut niveau comme les I/O de fichiers, de Socket, le multimedia ou la communication inter-processus. La raison principale derrière les streams est que les développeurs devraient être capables d'obtenir des données sur le web sans être obligés de les charger intégralement en mémoire.
Le standard propose 3 types de streams : Readable, Writable, et Transform. Il va sans dire que les cas d'utilisation de Readable et Writeable sont évidents, Transform pourrait servir pour chiffrer/déchiffrer des données à la volée, compresser/décompresser des images ou appliquer des filtres sur des vidéos.
Les Streams fonctionnent avec des paquets de données qui représentent l'unité de base qu'est capable de manipuler un stream. Un paquet peut contenir des données binaires ou textes, et un Stream peut combiner différents types de données. Est-ce qu'un stream peut contenir des données objet ou non, est une question qui est toujours en débat.
Les Streams sont des enveloppes autour des sources sous-jacentes. Il y a deux types de sources pour les streams de lecture : les sources push - qui poussent des données au consommateur, avec un mécanisme de pause et reprise de ce processus, et les sources de récupération – qui mettent à disposition des données de manière synchrone ou asynchrone en fonction des requêtes de l'utilisateur. Les Streams offrent une interface unifiée par dessus ces deux types de sources.
Un producteur envoie des données à un stream d'écriture qui est une enveloppe autour du puits sous-jacent. Le stream construit une file d'attente des écritures successives et les passe une par une au puits.
Les streams de transformation fonctionnent par branchement (ndt: pipe) d'un stream de lecture à un stream d'écriture. Plusieurs streams de transformation peuvent être enchaînés les uns à la suite des autres pour former une chaîne de branchements. Ce système utilise un mécanisme de retour de pression basé sur des signaux informant chacun des streams si l'un d'entre eux est surchargé. Chaque stream utilise un tampon pour gérer les données, stockant les fragments de données jusqu'à ce qu'il soit temps de les transférer au consommateur ou au puits sous-jacent. Le mécanisme de retour de pression est basé sur ces files d'attentes et leur stratégie de file d'attente. Un exemple d'une telle stratégie pourrait être de faire remonter la pression lorsqu'un des streams atteint plus de 3 fragments dans sa file d'attente.
Le standard propose une implémentation de référence et des tests écrits en ECMAScript 6 et traduits en ECMAScript 5 avec Traceur. Un travail a été commencé pour ajouter les Streams dans Chromium.
Nous sommes allés à la rencontre de Denicola pour en savoir plus sur ce projet.
InfoQ : Je comprends que les streams sont utiles mais ils sont déjà partout sur le web. Pourquoi une nouvelle API de streaming ?
DD : Les streams sont effectivement partout sur le web, mais ils ne sont malheureusement pas accessibles aux développeurs. Par exemple, lorsque vous faites une XMLHttpRequest, il n'y a pas moyen d'obtenir une réponse sans que celle-ci soit intégralement stockée en mémoire. Cela signifie que même si le navigateur utilise des techniques de streaming, pour implémenter le streaming vidéo par exemple, il n'y a pas moyen pour les développeurs de faire cela eux-mêmes pour les XMLHttpRequest. L'idée du standard Streams est de proposer un type de donnée JavaScript que les spécifications pourront commencer à retourner pour exposer les streams sous-jacents qu'ils utilisent déjà mais ne rendent pas accessibles aux développeurs.
InfoQ : Le but est-il d'intégrer cela à une prochaine version d'ECMAScript ?
DD : C'est une question intéressante et en fait nous avons prévu d'en discuter à la prochaine réunion TC39. Je suis partagé sur ce point. D'un côté, les streams I/O sont généralement une abstraction utile, et la spécification est écrite de manière agnostique. De nombreux langages comme le C++, le Java ou le C# ont les streams d'inclus. D'un autre côté, le standard ECMAScript est historiquement petit et concentré sur les primitives du langage, sans se préoccuper des choses comme l'I/O. Du coup, ajouter cela serait novateur et certainement perturbateur.
Actuellement, je crois que ce qui a le plus de sens est que la spécification reste indépendante du langage lui-même, mais on peut envisager des implémentations pour différents environnements JavaScript et pas seulement les navigateurs. Par exemple, la spécification ECMA-402 sur l'internationalisation est totalement indépendante, mais est implémentée sur plusieurs environnements JS. Le standard WHATWG URL a été développé après les bibliothèques de parsing d'URL de Node.js mais on peut espérer qu'elles évolueront pour refléter le standard au fil du temps. Et même quelque chose comme le standard Fetch pourrait en théorie être implémenté sur différents environnements comme un moyen standard de faire des requêtes HTTP.
InfoQ : Il y a aussi un travail en cours sur les Streams du côté de Blink. Savez-vous si d'autres s'y intéressent ?
DD : Oui, tout à fait ! Je suis en discussion permanente avec Microsoft et Mozilla, qui sont tous les deux très intéressés pour intégrer les Streams à leur navigateur. C'est encore très tôt mais il y a beaucoup de support.