Synchronous applications
Action → Request → HTML response → Action → …
-
The user queries a URL
GET /action?parameters HTTP/1.1 ...
-
The servers replies with some HTML.
-
The user leaves the page by one of the following:
- Clicking a link,
- Clicking a
submit
button, - reloading the page.
POST /other_action?parameters HTTP/1.1 ...
-
The server replies with more HTML.
And the state?
HTTP is stateless
In so-called Web 1.0 apps, the server is the only one responsible for keeping the state
- In the application logic (URLs, requests, etc.);
- In its local storage (sessions, databases);
- On the client (cookies).
Action → Request → HTML response → …
Collateral damage: the browser looses the state (except for its local storage) at each new action.
Demonstration: surf to some other page, then come back.
Time spent on these slides:
Synchronous browsing
Synchronous example
<form method='GET' action='http://stackoverflow.com/search'>
<input name='q' type='text' value='AJAX' />
<input type='submit' value='Ask' />
</form>
Asynchronous browsing
Asynchronous example
Asynchronous browsing
What is needed for asynchronous browsing?
Action ≠ Request
- JavaScript intercepts user actions (events).
Asynchronous requests (XMLHttpRequest
, Fetch API)
- JavaScript can initiat a request independently from the user actions,
- Requests do not interrupt browsing.
Server push (EventSource
, Web sockets)
- The server can send data to the client without waiting for a request.
XMLHttpRequest
Introduced by Microsoft in IE5, now a W3C standard.
- Sends POST or GET (and more) requests to the server;
- Does not block browser while waiting for the response.
- Runs an asynchronous callback when it receives the response.
/*************** Click ! ***************/
mydiv.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "../LICENSE");
xhr.onload = function(event) {
alert(xhr.response);
}
xhr.send();
}
Creation and preparation
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://.../action?params");
Callbacks
xhr.onload = function(event) {
console.log('Success');
}
xhr.onerror = function(event) {
console.log('Error');
}
xhr.onabort = function(event) {
console.log("Canceled by the user");
}
xhr.onprogress = function(event) {
console.log('Downloading...');
}
Sending data
xhr.setRequestHeader('Content-Type', 'text/plain')
xhr.send("Hello world !");
Emulating a form (can also send binary data)
var formData = new FormData();
formData.append('q', 'AJAX');
formData.append('hl', 'en');
// Content-Type: multipart/form-data by default
xhr.send(formData);
Sending JSON
var data = { primes : [2, 3, 5, 7],
even : [2, 4, 6, 8] };
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
Reading the response
xhr.onload = function() {
console.log(xhr.responseText); // Simple text
console.log(xhr.responseXML); // XML (if the response is indeed XML)
console.log(xhr.response); // Configurable (text by default)
}
Pre-parsing the response
xhr.responseType = "json";
xhr.onload = function() {
var obj = xhr.response; // transformed to a JavaScript object
console.log(obj.toto); // by the browser
}
responseType = "text"
: text (default),responseType = "document"
: DOM tree of a HTML document,responseType = "arraybuffer"
,responseType = "Blob"
: binary data.
Case study: StackOverflow API
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();
}
- Extracting input field data;
- Escaping special characters;
- Preparing the request for https://api.stackexchange.com;
- Waiting for a JSON-formatted response;
- Preventing form submission.
Case study: StackOverflow API
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>';
}
}
- The (JSON) response is converted to a JavaScript object;
- Building a list of the questions corresponding to our search;
- Inserting the result in the web page through the DOM;
- See the full API documentation: https://api.stackexchange.com/docs/.
References
-
Eloquent Javascript, Chapter 17.
-
MDN pages on AJAX (aussi en anglais).