Category Archives: Web

Iterator et iterable en javascript

Les concepts de d’itérator et d’itérable font leur entrée avec l’arrivée de ES6.

Iterator

Un iterator est un objet possédant une méthode next() et renvoyant quand elle est appelée une structure contenant les propriétés done et value

Exemple d’iterator

function myArrayIterator(arr) {
  var index = 0;
  return {
    next : function {
      if (index < arr.length) {
        return { done: false, value: arr[index++] };
      } else {
        return { done: true };
      }
    }
  }
}
var it = myArrayIterator(['s1', 's2']);
console.log(it.next()); // { done: false, value: "s1" }
console.log(it.next()); // { done: false, value: "s2" }
console.log(it.next()); // { done: true }

Cet iterator n’est pas iterable, c’est à dire qu’il ne peut pas être parcouru par une boucle for ..of

var it2 = myArrayIterator(['s1', 's2'])
for(var item of it2) { // TypeError: it2[Symbol.iterator] is not a function
  console.log(item);
}

Iterable

Afin d’être itérable, un objet doit implémenter la méthode @@iterator, cela signifie que l’objet (ou un des objets de sa chaîne de prototypes) doit avoir une propriété avec une clé Symbol.iterator. Cette méthode doit renvoyer un object iterator.

Rendons notre objet myArrayIterator iterable :

function myArrayIteratorIterable(arr) {
  var index = 0;
  return {
    [Symbol.iterator] : function () {
      return  {
        next : function () {
          if (index < arr.length) {
            return { done: false, value: arr[index++] };
          } else {
            return { done: true };
          }
        }
      }
    }
  }
}

var it2 = myArrayIteratorIterable(tab)
for(var item of it2) {
  console.log(item);
}
// s1
// s2

Exemple d’objet iterable

var batman = new (function() {
  var self = this;
  var index=0;
  
  
  this.nom = 'Wayne';  
  this.prenom = 'Bruce';
  this.parler = function() {
    console.log('Bonjour');
  }
  
  this[Symbol.iterator] = function () {
    var keys = Object.keys(self);
    return { 
      next : function() {
        if (index < keys.length) {
          return { done: false, value: self[keys[index++]] };
        } else {
          return { done: true };
        }
      }
    }
  };

})();

for(var item of obj) {
  console.log(i);
}

// "Wayne"
// "Bruce"
// function obj</this.parler()

 

 

 

 

 

JavaScript concepts clés : monothread et eventloop

Avant de présenter les différents patterns pour gérer l’asynchronisme en JavaScript, il est préférable de connaitre quelques concepts clés comme l’exécution sur un seul thread ou encore l’event loop. Cet article à pour but des les présenter.

Un seul thread pour l’application

JavaScript est un langage monothread, c’est à dire qu’à un instant T, un seul morceau de code s’exécute. On peut considérer, qu’une fonction est un morceau de code indivisible : quand un moteur JavaScript débute l’exécution d’une fonction il finit son exécution jusqu’à la fin (principe de « run to completion »).
Ce modèle possède un désavantage : l’appel d’un processus de longue durée bloque toute exécution tant que ce processus n’est pas terminé. Les éléments d’interface utilisateur cessent de répondre, les animations sont suspendues et aucun autre code de l’application ne peut s’exécuter. Généralement, le navigateur affiche un message de la sorte « Le script met trop de temps à répondre ».

Event loop

Il faut savoir que JavaScript gère la concurrence grâce à une « boucle d’évènements ». Ce modèle est différent de la gestion faite par des langages comme C ou Java. Afin de la comprendre ce qu’est l’event loop, trois parties importantes d’un moteur JavaScript méritent d’être présentées. Bien que l’implémentation des différents moteurs soient différentes, le principe reste vrai pour chacun d’eux.

eventloop1

Heap : La Heap est la partie la plus simple. C’est une zone de mémoire où vivent les objets (variables, fonctions …).

Stack : La stack est l’endroit où les fonctions en cours d’exécutions sont placées. Si une fonction A() lance une fonctin B() il y a deux niveaux dans la stack.
A chaque fois qu’une fonction est ajoutée à la stack elle est appelée « frame ». Les « frames » contiennent des pointeurs vers les fonctions situées dans la heap, vers les objects accessibles dans le scope de la fonction et bien sûr les paramètres d’appel de la fonction.

Queue : file de messages à traiter. Chaque message est associé à une fonction. Lorsque la pile est vide, c’est au tour du prochain message d’être traité. Ce message rempli alors la stack. Le traitement d’un message est fini quand la stack devient vide.
Si vous codez setTimeout(function() { console.log(‘pouet’); }, 10);, cette fonction anonyme sera mise dans la queue.
Aucune fonction dans la queue ne sera exécutée tant que la stack n’est pas vide. C’est pour cela que le deuxième paramètre de la fonction setTimeout assure un temps minimum avant l’exécution
et non pas un temps garanti.

Donnons vie à ce schéma.

 

Sources

https://thomashunter.name/blog/the-javascript-event-loop-presentation/
https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Boucle%C3%89v%C3%A9nements

 

 

Cache HTTP

Cache

Pour cacher, il est important de spécifier au moins les headers suivants :

  • Expires ou Cache-Control: max-age. Ceci permet au navigateur de connaître l’instant auquel il doit effectuer une requête au serveur.
  • Last-Modified ou Etag. Permet d’effectuer une requête conditionnelle.

 Header Etag

L’Etag est un identifiant assigné par le serveur à une ressource. La norme HTTP 1.1 ne définit pas comment le construire mais il est généralement calculé grâce à une fonction de hashage. Il représente en fait un checksum de la ressource. Si la ressource change alors l’ETAG sera différent.

L’Etag en lui même ne véhicule aucune information permettant au client (user agent) de déterminer s’il doit effectuer une nouvelle requête pour obtenir une nouvelle version de la ressource. Avec l’Etag comme seule information, le client effectuera dans tous les cas une requête vers le serveur. Le serveur confrontera l’Etag de la requête avec celui de a ressource pour renvoyer un code de retour 200 ou 304 (Etag identique). Pour empêcher le navigateur d’effectuer une requête à chaque demande il faut positionner le header Expires ou Cache-Control: max-age.

 Calcul de l’Etag

Bien que la spécification HTTP 1.1 n’indique en rien la manière de générer l’Etag, les serveurs utilisent généralement une fonction de hashage. La valeur hashée peut être :

  • le contenu de la ressource
  • la date de modification
  • un nombre de révision

Exemple d’implémentation :

  • Filtre de servlet calculant l’Etag sur le contenu de la réponse
  • FileETag directive d’apache pour les fichiers statiques

 Header Last-Modified

Date de dernière modification de la ressource renvoyée par le serveur. Utilisé pour les ressources statiques.

Etag ou Last-Modified ?

Les ressources statiques peuvent donc se voir affecter un Etag et/ou un header Last-Modified tandis que les ressources dynamiques se veront plus généralement affecter un Etag. En effet, de par sa nature, l’Etag peut être utilisé pour les ressources statiques et dynamiques (hash du contenu ou hash d’un attribut du fichier). La date de modification est plus difficile à calculer pour une page dynanique (ensemble de requêtes SQL et de HTML) que pour un simple fichier (attribut mtime). C’est pour cela que les ressources dynamiques portent principalement des Etag et que les ressources statiques portent le header Last-Modified.

Code de retour 304

La réponse 304 signifie que la copie de la ressource que dispose le client n’a pas été modifié depuis sa dernière demande. Le navigateur réutilise alors sa version de la ressource. Cela permet de ne pas renvoyer le contenu de la ressource ce qui minimise minimise le temps d’affichage.

Requête conditionnelle

Lorsque le cache de la ressource est expiré, le navigateur envoie une requête conditionnelle. La requête dispose des headers suivants :

  • If-Modified-Since : contient la date de dernière modification de la ressource locale
  • If-None-Match : etag de la copie locale

Une fois que le serveur a reçu la requête, il détermine si la ressource est périmée. Si c’est le cas, le contenu de la ressource est renvoyé au client avec un code HTTP 200. Le navigateur utilise alors le corps de la réponse et la cache à nouveau.

Header Cache-Control

Ce header est à la fois un header de requête et de réponse.

Requête

Si un navigateur envoie une requête comportant le header Cache-Control: max-age=0 (aka end-to-end revalidation) alors tous les caches entre le navigateur et le serveur revalideront la ressource. Pour cela le navigateur envoie également les headers permettant d’effectuer une requête conditionnelle (If-Modified-Since et If-None-Match). La réponse peut être un code 304.

Si le navigateur envoie une requête comportant le header Cache-Control : no-cache (aka end-to-end reload) alors le serveur ne doit pas renvoyer une copie de la ressource.

Par exemple, Firefox envoie le header « Cache-Control : max-age=0 » lors d’un F5 et le header « Cache-Control : no-cache » lors d’un ctrl+F5

Réponse

  • no-cache : Le navigateur doit revalider la ressource à chaque appel
  • max-age : Durée maximum de rétention de la ressource dans le cache navigateur. Cette directive outrepasse l’en-tête Expires
  • no-store : le cache navigateur ne doit pas stocker la ressource en local

Header Expires

Date à laquelle le cache expire. Header de la norme HTTP 1.0 renvoyé par le serveur. Sur les navigateurs modernes « cache control » prévaut.

Quand le cache a expiré le navigateur envoie une requête conditionnelle au serveur avec les headers If-Modified-Since et If-None-Match.

 

Enchainement des requêtes

diagramme sequence http requete1 Le navigateur ne connaît pas la ressource. Il effectue une requête GET pour l’obtenir. request1

2Le serveur renvoie la ressource (HTTP 200) avec des headers de cache.

  • Le header Cache-Control indique que la ressource est cachée 1h (max-age=3600)
  • Le header Expires est également positionné est indique bien que la ressource doit être considérée comme périmée dans une heure. Le header expire est redondant avec Cache-Control
  • La date de dernière modification et un Etag sont renvoyés permettant d’effectuer une requête conditionnelle à l’expiration du cache

response23Le cache local du navigateur est arrivé à expiration. Il demande au serveur si la ressource qu’il possède est toujours valide. Pour cela il effectue une requête conditionnelle.request3

4La ressource n’ayant pas été modifiée, le serveur renvoie un code HTPP 304 autorisant le navigateur à réutiliser sa copie locale. La ressource est de nouveau valide durant 1 heure. response 4

Sources

http://blogs.telerik.com/fiddler/posts/12-11-05/understanding-http-304-responses
http://en.wikipedia.org/wiki/HTTP_ETag
http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/
http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/
http://stackoverflow.com/questions/10314174/difference-between-pragma-and-cache-control-headers
http://stackoverflow.com/questions/998791/if-modified-since-vs-if-none-match
http://stackoverflow.com/questions/1046966/whats-the-difference-between-cache-control-max-age-0-and-no-cache
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4

URL, URN, URI quelles différences ?

Commençons pas la définition officielle de la RFC 3986 :

A URI can be further classified as a locator, a name, or both. The term « Uniform Resource Locator » (URL) refers to the subset of URIs that, in addition to identifying a resource, provide a means of locating the resource by describing its primary access mechanism (e.g., its network « location »). The term « Uniform Resource Name » (URN) has been used historically to refer to both URIs under the « urn » scheme [RFC2141], which are required to remain globally unique and persistent even when the resource ceases to exist or becomes unavailable, and to any other URI with the properties of a name.

URI_Euler_Diagram_no_lone_URIs.svgURI : Une URI identifie une ressource soit par son nom, soit pas sa localisation soit par les deux. Il existe deux types d’URI :
- URL : Uniform Resource Locator
- URN : Uniform Resource Name

 

URL : une URL est un sous ensemble des URI qui spécifie la localisation d’une ressource et comment la récupérer grâce au schéma : http, ftp, smb, file, …

URN : l’URN n’implique pas de disponibilité de la ressource, elle identifie juste de manière unique cette dite ressource sans décrire ni comment ni où la trouver. Elle se représente obligatoirement via le schéma URN.

Exemples d’URL :
mailto:someone@example.com
http://www.google.fr/
file:///home/someuser/somefile.txt

Exemples d’URN :
urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C
urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66

Je n’ai malheureusement pas trouvé d’exemple d’URI étant à la fois URL et URN.

Explication par analogie

Pour expliquer de façon concrète, je vais m’appuyer sur la réponse Roger Pate sur stackoverflow.

De manière générale, une URI identifie et une URL localise. Ces deux notions ne sont pas antinomiques puisque localiser revient à identifier, mais identifier n’est pas forcément localiser. C’est pour cela qu’une URL est une URI, mais que toutes les URI ne sont pas des URL.

Exemple

Roger Pate

Ces quelques lettres représentent un nom qui par définition permet d’identifier une personne. Cela ne peut pas s’apparenter à une URL car il ne véhicule aucune information permettant de localiser ou de contacter la personne.

On pourrait le rapprocher d’une URN. En effet, une URN peut être employée pour parler d’une ressource sans que cela ne préjuge de son emplacement ou de la manière de la référencer. Elle est toutefois très restrictive au sujet de l’unicité dans le temps et dans l’espace. Pour continuer avec l’exemple précédent, dans le monde, plusieurs personnes peuvent s’appeler Roger Pate. Quand bien même il n’existe qu’un seul Roger Pate sur Terre, d’autres Roger Pate ont sûrement existé avant lui. Et si ce n’est pas le cas, rien n’enpêche Roger Pate de transmettre à un de ses descendants sont nom et prénom. Le nom n’est pas unique dans le temps ni dans l’espace, cela ne fait donc pas une bonne URN.

 

4914 West Bay Street, Nassau, Bahamas

Ceci est une adresse qui permet de localiser un lieu. On peut l’apparenter à une URL car elle identifie (indirectement) Roger Pate tant que « résident de … »

 

Syntaxe des URI

Toutes les URIs sont formées de la sorte :
<scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]
Pour les détails, voir la page wikipedia

Toutefois, les exemples suivants sont également des URI ; plus précisément des références d’URI :
- relative/path/to/resource.txt
- /../../resource.txt
- /resource.txt#frag01

 

Sources
http://stackoverflow.com/questions/176264/whats-the-difference-between-a-uri-and-a-url
http://stackoverflow.com/questions/4913343/what-is-the-difference-between-uri-url-and-urn
http://damnhandy.com/2011/01/18/url-vs-uri-vs-urn-the-confusion-continues/ http://en.wikipedia.org/wiki/Uniform_Resource_Identifier

www or not www

Petits tour d’horizon des arguments pour et contre l’utilisation du www dans l’url :

Pour :

  • Le www est le sous domaine standard du domaine principale. Comme tout sous-domaine, il peut bénéficier d’une entrée DNS. Qui dit IP différente dit potentiellement serveurs différents.
  • Permet de distinguer les différents sous domaines (www, mail, ftp, blog, …)
  • Symétrie visuelle de l’url (www.XXX.com)
  • Visibilité des cookies : positionner un cookie sur le domaine racine fera qu’il sera visible sur tous les autres sous domaines.

Contre :

  • Les sous domaines ne sont pas obligatoires
  • Difficulté de prononciation du www
  • Rallonge l’url

Dans tous les cas, il est fortement conseillé de faire une redirection propre (301) pour n’autoriser qu’une forme d’URL (problématique SEO). Exemple pour supprimer le www de l’url :

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.jerep6\.fr$
RewriteRule (.*) http://jerep6.fr/$1 [L,R=301]

Sources :
http://stackoverflow.com/questions/1109356/www-or-not-www-what-to-choose-as-primary-site-name
http://www.codinghorror.com/blog/2008/04/the-great-dub-dub-dub-debate.html
http://computer.howstuffworks.com/internet/basics/question180.htm
http://creativebriefing.com/how-to-brand-your-websites-url-part-1-to-www-or-not-to-www/
http://no-www.org/

Cookies et les domaines

Visibilité des cookies entre domaines

D’une manière générale, un cookie n’est visible que pour le domaine pour lequel, et par lequel il a été émis. Le navigateur applique la « politique de la même source ».

Plus précisément, un cookie d’un domaine est visible sur ses sous domaines. Le contraire n’est pas vrai. Un cookie d’un sous domaine n’est pas visible à partir d’un domaine de plus haut niveau De plus, il est impossible à partir d’un domaine de plus haut niveau d’écrire un cookie sur un sous domaine. Il est en revanche autorisé pour un sous domaine positionner un cookie sur son sur domaine.

En résumé, un domaine de plus haut niveau ne peut rien faire sur un sous domaine.

Attribut domain du cookie

Lors de la réception du cookie, si ce dernier ne possède pas d’attribut domain le domaine du cookie est celui de la requête. Si l’attribut domain est renseigné de manière valide, sa valeur sera préfixée par le navigateur d’un « . » avant d’être utilisée.
Le navigateur refuse tous les cookies dont l’attribut domain ne correspond pas au domaine effectif de la requête. Les mêmes règles s’applique lors de l’envoi des cookies. Cela interdit aux sites de écrire / lire des cookies qui ne leur sont pas destinés.

Point en tant que préfixe du domaine

Le point préfixant le domaine du cookie signifie que ce dernier sera accessible par les sous domaines. Ainsi un cookie ayant pour domaine .jerep6.fr sera visible sur www.jerep6.fr. Un cookie dont l’attribut domain est « jerep6.fr » ne sera quant à lui pas disponible sur le domaine www.jerep6.fr du fait de l’absence du point au début de l’attribut domain. Lire la suite »