Ajax : Asynchronous JavaScript & XML

Alexandre Niveau
GREYC — Université de Caen
En partie adapté du cours de Jean-Marc Lecarpentier

Nouveaux besoins

  • JavaScript permet de créer des pages interactives : les actions de l'internaute modifient la page
  • Cependant, ça ne suffit pas toujours :
    • rafraîchissement automatique (webmail, chat…)
    • autocomplétion, suggestions
    • « exploration » (cartes, infinite scrolling…)
    • contenu modifiable
    • notes, votes, « likes », etc.
  • Pages interactives qui communiquent avec le serveur

Idée

  • JavaScript doit donc communiquer directement avec le serveur :
    • gérer la connexion HTTP et l'envoi de données GET ou POST
    • gérer la réception de la réponse du serveur
  • Tout cela est géré grâce à une API : XMLHttpRequest

XMLHttpRequest

  • Interface d'origine développée par Microsoft pour leur webmail Outlook Web Access
  • Incorporée ensuite dans IE 5.0 (sorti en mars 1999)
  • Copiée par Mozilla, implémentée comme un objet JS XMLHttpRequest dans Mozilla 0.6 (décembre 2000)
  • Cette version devient un standard de facto
  • Normalisé par le W3C à partir de 2006, puis XMLHttpRequest level 2 à partir de 2008
  • Depuis 2011, plus qu'un seul standard, implémenté dans la plupart des navigateurs (IE > 9, voir tableau de compatibilité)

Principe de XHR

  • On crée une requête, et on ajoute un listener dessus avant de l'envoyer
  • Le listener sera appelé lors de la réception de la réponse (fonction de callback)
    	let xhr = new XMLHttpRequest();
    	xhr.open("GET", "adresse_ressource");
    	xhr.addEventListener("load", function () {
    		alert(xhr.response);
    	});
    	xhr.send();
    
  • (démo)
  • N.B. : la réponse n'est pas forcément du XML !… Et le protocole pas forcément du HTTP.
  • Attention : il faut ajouter le listener avant de lancer la requête avec send !

Ajax

Modèle d'application classique vs Ajax Communication synchrone entre client et serveur Communication asynchrone entre client et serveur
Modèle classique du web comparé au modèle Ajax. Source : article original de Jesse James Garett
  • L'utilisation de XMLHttpRequest (XHR) permet un nouveau modèle des interactions client-serveur
  • Terme Ajax apparu début 2005 : Asynchronous Javascript and XML
  • Principe : au lieu d'être synchrone, la communication client-serveur est asynchrone
  • Ajax désigne l'ensemble des technologies nécessaires aux applications web asynchrones

Types de réponse

  • Au départ XMLHttpRequest était prévu pour récupérer du XML/HTML : dans les deux cas, la réponse à la requête est à la fois
    • dans xhr.responseText sous forme de texte brut
    • dans xhr.responseXML sous forme d'objet DOM
  • Dans XHR2, c'est plus simple :
    • on positionne l'attribut responseType, par exemple à text pour récupérer du texte (défaut) ou document pour récupérer un document HTML ou XML
    • la réponse est dans tous les cas dans l'attribut response
  • On n'utilise plus responseXML et responseText
  • Démo de récupération d'un fragment HTML
  • On récupère rarement du HTML, en général ce sont des données pures qui nous intéressent (la mise en forme est alors faite côté client)
  • Le XML étant lourd à transmettre, fastidieux à manipuler à la main, et relativement complexe à parser, un format de données texte s'est peu à peu imposé : le JSON, JavaScript Object Notation

JSON

  • Comme son nom l'indique, le JSON reprend la notation des objets JavaScript :
    {
    	"name": "John Smith",
    	"address": {
    		"city": "New York, NY",
    		"streetAddress": "21 2nd Street"
    	},
    	"phoneNumbers": [
    		"212 732-1234",
    		"646 123-4567"
    	]
    }
      
  • Historiquement, on récupérait du JSON dans xhr.responseText, et on le convertissait en objet JS en exécutant le code (pas propre), ou avec la fonction JSON.parse()
  • Remarque : l'inverse de JSON.parse() est JSON.stringify(), qui renvoie une sérialisation en JSON d'un objet JavaScript

JSON avec XHR2

  • XHR2 permet de manipuler le JSON plus facilement
  • Il suffit de dire explicitement qu'on demande du JSON, en modifiant l'attribut responseType du XHR
  • L'objet récupéré sera dans xhr.response (comme pour les autres modes de réponse)
    let xhr = new XMLHttpRequest();
    xhr.open('GET', 'adresse_ressource');
    xhr.responseType = "json";
    xhr.addEventListener("load", function () {
    	console.log(xhr.response);
    });
    xhr.send();
      
  • (voir démo)
  • Malheureusement pas implémenté dans IE (≤11)

Événements déclenchés par l'objet XMLHttpRequest

  • load : se déclenche lorsque la requête s'est correctement terminée
  • error : se déclenche lorsque la requête ne s'est pas terminée
  • abort : se déclenche lorsque la requête a été abandonnée (par exemple avec xhr.abort()
  • timeout : se déclenche lorsque la requête a dépassé la durée maximale autorisée

Autres propriétés de XMLHttpRequest

  • status : le code HTTP renvoyé par la requête
  • statusText : la chaîne correspondant au code HTTP
  • overrideMimeType(String mimetype) : force le type MIME de la réponse
  • setRequestHeader(String header, String value) : en-tête HTTP à envoyer

Requêtes autres que GET

  • Requête POST :
      xhr.open('POST', 'page.php');
      xhr.addEventListener('load', monCallback);
      xhr.setRequestHeader('Content-type', 
                 'application/x-www-form-urlencoded');
      xhr.send('tutu=0&toto=1');
    
  • Les requêtes POST sont simplifiées en XHR2 avec l'interface FormData
  • Rien n'empêche également d'utiliser les autres méthodes de HTTP, comme PUT et DELETE

Nouvelle API : fetch

  • API plus récente que XHR, pour faire le même genre de choses : fetch
  • Se veut plus simple et propre que XHR
  • Utilise une nouveauté ES6 : les promesses, qui simplifient la gestion des callbacks (notamment pour les cas d'erreurs)
  • Un tutoriel sur fetch (developers.google.com)