32. ➔ Très bien supporté ➔ Performances
➔ API simple ➔ API synchrone
➔ Mis en avant par de nb ➔ Sérialisation
compagnies/projets ➔ Requêtes
➔ Complexité
➔ "indexation" manuelle
➔ Maintien intégrité
38. API asynchrone
function IndexedDBAdapter() {
function IndexedDBAdapter() {
this.db = null;
this.db = null;
var request = indexedDB.open("contactApp");
var request = indexedDB.open("contactApp");
request.onsuccess = function(e) {
request.onsuccess = function(e) {
this.db = e.target.result;
this.db = e.target.result;
}.bind(this);
}.bind(this);
request.onfailure = function(e) {
request.onfailure = function(e) {
console.log("Could not connect to the database");
console.log("Could not connect to the database");
}}
};
};
39. Création d'un dépôt
IndexedDBAdapter.prototype.create = function(storeName) {
IndexedDBAdapter.prototype.create = function(storeName) {
var v = "1.0";
var v = "1.0";
var request = this.db.setVersion(v);
var request = this.db.setVersion(v);
request.onsuccess = function(e) {
request.onsuccess = function(e) {
var store = this.db.createObjectStore(storeName, {
var store = this.db.createObjectStore(storeName, {
"keyPath": "id",
"keyPath": "id",
"autoIncrement": true
"autoIncrement": true
});
});
};
};
request.onblocked = function(e) {
request.onblocked = function(e) {
console.log("The database is open in another tab.");
console.log("The database is open in another tab.");
};
};
};
};
40. Persistence d'un objet
IndexedDBAdapter.prototype.save(storeName, object, callback)
IndexedDBAdapter.prototype.save(storeName, object, callback)
{{
var trans = db.transaction([storeName],
var trans = db.transaction([storeName],
IDBTransaction.READ_WRITE, 0);
IDBTransaction.READ_WRITE, 0);
var store = trans.objectStore(storeName);
var store = trans.objectStore(storeName);
var request = store.put(object);
var request = store.put(object);
request.onsuccess = function(e) {
request.onsuccess = function(e) {
callback(object);
callback(object);
};
};
};
};
41. Requête simple
IndexedDBAdapter.prototype.all(storeName, callback) {
IndexedDBAdapter.prototype.all(storeName, callback) {
var trans = db.transaction([storeName],
var trans = db.transaction([storeName],
IDBTransaction.READ_WRITE, 0);
IDBTransaction.READ_WRITE, 0);
var store = trans.objectStore(storeName);
var store = trans.objectStore(storeName);
var keyRange = IDBKeyRange.lowerBound(0);
var keyRange = IDBKeyRange.lowerBound(0);
var request = store.openCursor(keyRange);
var request = store.openCursor(keyRange);
request.onsuccess = function(e) {
request.onsuccess = function(e) {
var cursor = e.target.result;
var cursor = e.target.result;
if (cursor) {
if (cursor) {
callback(cursor.value);
callback(cursor.value);
cursor.continue();
cursor.continue();
}}
};
};
};
};
42. Key Ranges
IDBKeyRange.upperBound(x); // <= x
IDBKeyRange.upperBound(x); // <= x
IDBKeyRange.upperBound(x, true); // < x
IDBKeyRange.upperBound(x, true); // < x
IDBKeyRange.lowerBound(y); // >= y
IDBKeyRange.lowerBound(y); // >= y
IDBKeyRange.lowerBound(y, true); // > y
IDBKeyRange.lowerBound(y, true); // > y
IDBKeyRange.bound(x, y); // >= x && <= y
IDBKeyRange.bound(x, y); // >= x && <= y
IDBKeyRange.bound(x, y, true, false); // > x && <= y
IDBKeyRange.bound(x, y, true, false); // > x && <= y
La difficulté de la tâche dépend de l'appli, en particulier des fonctionnalités devant être utilisables hors connexion (et de celles qui sont difficiles à supporter hors connexion, comme la recherche globale) Difficile de convertir une appli au offline si elle n'est pas conçue à la base comme une appli essentiellement client-side (single page app) avec un backend se comportant en dépôt de données &quot; simple &quot; En fonction de l'application, on choisira une conception &quot; modale &quot; (l'user choisit explicitement de basculer en offline, d'où un chargement local initial des données), notamment si l'appli présente des données hors de contrôle de l'user (ex : feedreader), ou &quot; modeless &quot; (ex : webmail, gestion de tâches...) Dans tous les cas, supporter une utilisation offline complexifie l'appli, il convient donc de s'assurer que ce type d'utilisation est pleinement justifié
Le cache d'une appli est limité à 5 Mo (à checker) Diffère de la mise en cache &quot; classique &quot; des navigateurs, qui est plus volatile
Une fois que les ressources sont mises en cache, le cache n'est mis à jour que si le manifeste change
Autre pb : le navigateur n'essaiera même pas de charger toute ressource qui n'est pas mentionnée dans le manifeste, les URIs type API et autre doivent donc être mentionnées dans la section NETWORK
On détecte l'event 'updateready' qui signale une mise à jour du manifeste et donc une MAJ potentielle des ressources pour en avertir l'user et rafraîchir la page, donnant ainsi à l'user l'accès aux nouvelles ressources
Plus facile à dire qu'à faire (tout dépend de l'appli) : l'idée est dans un premier temps d'encapsuler les appels XHR dispersés dans l'appli dans un module type Repository : l'appli ne parle plus directement à un serveur mais à un objet dépôt de données qui, pour l'instant, fait des appels XHR
Maintenant que l'application est découplée du réseau, nous pouvons faire en sorte que notre objet &quot; dépôt &quot; persiste localement les données chargées depuis le serveur
API permettant de lire/écrire des reps et fichiers dans une portion &quot; sandboxée &quot;, par application, du FS Uniquement pour Chrome >= 13.0 pour toutes les fonctionnalités Tous les objets sont préfixés par webkit
Lorsque window. requestFileSystem est appellé pour la première fois, le bac à sable est créé. Il peut être temporaire (et potentiellement supprimé par le browser à sa discrétion) ou persistant, ce qui nécessite de demander l'autorisation à l'utilisateur Il existe une API pour checker le statut et l'utilisation du quota
SessionStorage supprime les données lorsque le navigateur est fermé
Le quota de 5Mo est mentionné dans la spec W3C, dans la pratique cela dépend des versions des navigateurs... Pas de transactions → risque de pb d'accès concurrent (race condition) si l'appli est utilisé dans 2 onglets par exemple
Si le support d'IE 7 est requis, il existe un polyfill simple qui va stocker les données dans le cookie
Inconvénients : - nbreuses requêtes - charge sur les serveurs - latence entre 2 polls (pas de vrai temps réel à moins de poller toutes les secondes)
Plus proche du temps réel, mais plus complexe à mettre en place. Dans le cas du push de micro-modifs, le nb/poids des requêtes reste conséquent (surtout compte tenu des headers HTTP) Une variante : le push streaming où l'on ne referme pas la connexion à chaque event mais où on envoie une réponse en plusieurs fois ; pb : mal supporté par certains proxys
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Socket.IO utilise le meilleur moyen à sa dispo : - websockets - Flash socket - long polling - Ajax streaming - forever iframe - JSONP polling
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé
Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S'efforce de traverser proxys et firewall Protocole RFCisé