Applications synchrones
Action → Requête → Réponse HTML → Action → …
-
L’utilisateur demande une URL
GET /action?parametres HTTP/1.1 ...
-
Le server répond avec du HTML.
-
L’utilisateur quitte la page en
- Cliquant un lien,
- Cliquant un bouton de type
submit
, - rafraîchissant.
POST /autre_action?parametres HTTP/1.1 ...
-
Le server répond avec de l’autre HTML.
Et l’état ?
HTTP est sans état
Dans le Web 1.0, le server est le seul responsable du maintien de l’état
- dans la logique de l’application (URLs, requêtes, etc.)
- dans son stockage local (sessions, bases de données),
- chez le client (cookies).
Action → Requête → Réponse HTML → …
Dommage collatéral : le browser perd l’état (à l’exception de son stockage local) à chaque nouvelle action.
Démonstration : naviguez vers la racine, puis revenez.
Temps passé sur ces slides :
Navigation synchrone
Exemple synchrone
<form method='GET' action='http://stackoverflow.com/search'>
<input name='q' type='text' value='AJAX' />
<input type='submit' value='Ask' />
</form>
Navigation asynchrone
Exemple asynchrone
Navigation asynchrone
Quels éléments pour une navigation asynchrone ?
Action ≠ Requête
- JavaScript intercepte les actions (évènements) de l’utilisateur.
Requêtes asynchrones (XMLHttpRequest
, Fetch API)
- JavaScript peut initier une requête indépendamment des actions de l’utilisateur,
- Les requêtes n’interrompent pas la navigation.
Server push (EventSource
, Web sockets)
- Le serveur peut envoyer des données au client sans attendre une requête.
XMLHttpRequest
Introduit par Microsoft dans IE5, maintenant un standard W3C.
- Envoie des requêtes POST ou GET (ou autre) vers le server ;
- Ne bloque pas le browser en attendant la response ;
- Exécute une callback asynchrone à l’arrivée de la response.
/*************** Cliquez ! ***************/
mydiv.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "../LICENSE");
xhr.onload = function(event) {
alert(xhr.response);
}
xhr.send();
}
Creation et préparation
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://.../action?params");
Callbacks
xhr.onload = function(event) {
console.log('Succes');
}
xhr.onerror = function(event) {
console.log('Erreur');
}
xhr.onabort = function(event) {
console.log("Annulé par l'utilisateur");
}
xhr.onprogress = function(event) {
console.log('Téléchargement...');
}
Envoyer des données
xhr.setRequestHeader('Content-Type', 'text/plain')
xhr.send("Hello world !");
Simuler un formulaire (peut aussi envoyer des données binaires)
var formData = new FormData();
formData.append('q', 'AJAX');
formData.append('hl', 'en');
// Content-Type: multipart/form-data par defaut
xhr.send(formData);
Envoyer du JSON
var data = { primes : [2, 3, 5, 7],
even : [2, 4, 6, 8] };
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
Lire la réponse
xhr.onload = function() {
console.log(xhr.responseText); // Texte simple
console.log(xhr.responseXML); // XML (si la réponse est dans ce format)
console.log(xhr.response); // Configurable (texte par défaut)
}
Pré-traitement de la réponse par le browser
xhr.responseType = "json";
xhr.onload = function() {
var obj = xhr.response; // transformé en objet JavaScript
console.log(obj.toto); // par le browser
}
responseType = "text"
: texte (default),responseType = "document"
: arbre DOM d’un document HTML,responseType = "arraybuffer"
,responseType = "Blob"
: données binaires.
Étude de cas : API StackOverflow
document.querySelector('#SO').onsubmit = function(e) {
var query = encodeURIComponent(document.querySelector('#query').value);
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.stackexchange.com/2.2/search/advanced'
+ '?q=' + query + '&site=stackoverflow');
xhr.onload = callback;
xhr.responseType = 'json';
xhr.send();
e.preventDefault();
}
- Récupération du contenu du champs de texte ;
- Échappement des caractères spéciaux ;
- Préparation de la requête à https://api.stackexchange.com ;
- On attend un résultat au format JSON ;
- On arrête la soumission du formulaire.
Étude de cas : API StackOverflow
var callback = function(e) {
if (xhr.response && xhr.response.items) {
var liste = xhr.response.items;
for (var i = 0; i < liste.length; i++) {
document.querySelector('#answers > ul').innerHTML =
'<li>' + liste[i].title + '</li>';
}
} else {
document.querySelector('#answers').innerHTML =
'<p>Pas de résultats.</p>';
}
}
- La réponse (au format JSON) est automatiquement convertie en objet JavaScript ;
- On construit une liste des questions répondant aux critères ;
- On insère le résultat dans la page via le DOM ;
- Voir la documentation complète de l’API : https://api.stackexchange.com/docs/.
Lectures
-
Eloquent Javascript, Chapitre 17.
-
Pages AJAX du MDN (aussi en anglais).