SlideShare uma empresa Scribd logo
1 de 69
Baixar para ler offline
HTML 5
  stockage local
& synchronisation


 Raphaël Rougeron   @goldoraf
Une mutation est en cours


                            Pages HTML




  Serveur          Client




                             Single-Page
                             Application
            JSON
Form validation
                        Geolocation
Drag n' Drop API
       Web Notifications
                              Canvas
   WebGL              Video
         Audio
                         File API
 Web Workers

                      Web Sockets
Stockage local
1er bénéfice : le offline ?
1er bénéfice : économiser le
         serveur !




Source : HTML5 Web Sockets: A Quantum Leap in Scalability for the Web
http://soa.sys-con.com/node/1315473
4 étapes
Etape 1
   Rendre les ressources
disponibles hors connexion
Application Cache
<html manifest="cache.manifest">
 <html manifest="cache.manifest">




      CACHE MANIFEST
       CACHE MANIFEST

      CACHE:
       CACHE:
      index.html
       index.html
      css/style.css
       css/style.css
      img/logo.png
       img/logo.png
      js/main.js
       js/main.js

                  text/cache­manifest
!
Avoir un manifeste
change complètement
les règles d'accès aux ressources
CACHE MANIFEST
 CACHE MANIFEST

# v.1.2­build1234
 # v.1.2­build1234
CACHE:
 CACHE:
index.html
 index.html
css/style.css
 css/style.css
img/logo.png
 img/logo.png
js/main.js
 js/main.js
CACHE MANIFEST
 CACHE MANIFEST
# v.1.2­build1234
 # v.1.2­build1234
CACHE:
 CACHE:
index.html
 index.html
css/style.css
 css/style.css
img/logo.png
 img/logo.png
js/main.js
 js/main.js
NETWORK
 NETWORK
/sync
 /sync
/api/*
 /api/*
http://api.twitter.com
 http://api.twitter.com
CACHE MANIFEST
 CACHE MANIFEST
# v.1.2­build1234
 # v.1.2­build1234
CACHE:
 CACHE:
index.html
 index.html
css/style.css
 css/style.css
img/logo.png
 img/logo.png
js/main.js
 js/main.js
NETWORK
 NETWORK
/sync
 /sync
/api/*
 /api/*
http://api.twitter.com
 http://api.twitter.com
FALLBACK
 FALLBACK
images/large/ images/offline.jpg
 images/large/ images/offline.jpg
*.html /offline.html
 *.html /offline.html
window.applicationCache

     status
     UNCACHED
     IDLE
     CHECKING
     DOWNLOADING
     UPDATEREADY
     OBSOLETE
var appCache = window.applicationCache;
 var appCache = window.applicationCache;
appCache.addEventListener('updateready', function(e) {
 appCache.addEventListener('updateready', function(e) {
    if (appCache.status == appCache.UPDATEREADY) {
     if (appCache.status == appCache.UPDATEREADY) {
      appCache.swapCache();
       appCache.swapCache();
      if (confirm('Une nouvelle version est dispo')) {
       if (confirm('Une nouvelle version est dispo')) {
        window.location.reload();
         window.location.reload();
      }
       }
    }
     }
}, false);
 }, false);
>= 10 ?   >= 3.5   >= 4.0    >= 4.0     >= 10.6




          >= 3.2    >= 2.1    >= 11.0
Etape 2
Découpler l'application du
        réseau
var Todo = Backbone.Model.extend({
 var Todo = Backbone.Model.extend({
    toggle: function() {
     toggle: function() {
      this.save({done: !this.get("done")});
       this.save({done: !this.get("done")});
    },
     },
    clear: function() {
     clear: function() {
      this.destroy();
       this.destroy();
    }
     }
});
 });
var TodoList = Backbone.Collection.extend({
 var TodoList = Backbone.Collection.extend({
    model: Todo,
     model: Todo,
    done: function() {
     done: function() {
      return this.filter(function(todo){ return todo.get('done'); });
       return this.filter(function(todo){ return todo.get('done'); });
    },
     },
    remaining: function() {
     remaining: function() {
      return this.without.apply(this, this.done());
       return this.without.apply(this, this.done());
    }
     }
});
 });
Backbone.Sync
●   create()   POST   /collection

●   read()     GET    /collection[/id]

●   update()   PUT    /collection/id

●   delete()   DELETE /collection/id
Etape 3
Stocker localement les
      données
3 options
FileSystem API



  !    seulement
window.requestFileSystem  = window.requestFileSystem 
 window.requestFileSystem  = window.requestFileSystem 
                          || window.webkitRequestFileSystem;
                           || window.webkitRequestFileSystem;
window.requestFileSystem(window.TEMPORARY, 
 window.requestFileSystem(window.TEMPORARY, 
                         5*1024*1024,
                          5*1024*1024,
                         onInitFs, errorHandler);
                          onInitFs, errorHandler);
                      

window.webkitStorageInfo.requestQuota(window.PERSISTENT, 
 window.webkitStorageInfo.requestQuota(window.PERSISTENT, 
                                      5*1024*1024,
                                       5*1024*1024,
                                      initFS, errorHandler);
                                       initFS, errorHandler);
function initFS(grantedBytes) {
 function initFS(grantedBytes) {
  window.requestFileSystem(PERSISTENT, grantedBytes, 
   window.requestFileSystem(PERSISTENT, grantedBytes, 
                           onInitFs, errorHandler);
                            onInitFs, errorHandler);
}}
FileError

code
QUOTA_EXCEEDED_ERR
NOT_FOUND_ERR
SECURITY_ERR
INVALID_MODIFICATION_ERR
INVALID_STATE_ERR
function onInitFs(fs) {
 function onInitFs(fs) {
  fs.root.getFile('data.txt', {create: true}, function(entry) {
   fs.root.getFile('data.txt', {create: true}, function(entry) {
    entry.file(function(file) {
     entry.file(function(file) {
       
        
       var reader = new FileReader();
        var reader = new FileReader();
       reader.onloadend = function(e) {
        reader.onloadend = function(e) {
         repository.init(JSON.parse(e.target.result));
          repository.init(JSON.parse(e.target.result));
       };
        };
       reader.readAsText(file);
        reader.readAsText(file);
    
     
    }, errorHandler);
     }, errorHandler);
  }, errorHandler);
   }, errorHandler);
}}
FileEntry
name
fullpath
isFile
isDirectory
…
file()
createWriter()
moveTo()
copyTo()
remove()
...
function persistData(fs, data) {
 function persistData(fs, data) {
  fs.root.getFile('log.txt', {create: true}, function(entry) {
   fs.root.getFile('log.txt', {create: true}, function(entry) {
    entry.createWriter(function(writer) {
     entry.createWriter(function(writer) {
      writer.onwriteend = function(e) {
       writer.onwriteend = function(e) {
        console.log('Write completed.');
         console.log('Write completed.');
      };
       };
      writer.onerror = function(e) {
       writer.onerror = function(e) {
        console.log('Write failed: ' + e.toString());
         console.log('Write failed: ' + e.toString());
      };
       };
      var bb = new BlobBuilder();
       var bb = new BlobBuilder();
      bb.append(JSON.stringify(data));
       bb.append(JSON.stringify(data));
      writer.write(bb.getBlob('text/plain'));
       writer.write(bb.getBlob('text/plain'));
    }, errorHandler);
     }, errorHandler);
  }, errorHandler);
   }, errorHandler);
}}
Web Storage
localStorage et sessionStorage
Un simple dépôt clé-valeur
localStorage.setItem("foo", "bar");
 localStorage.setItem("foo", "bar");


localStorage.setItem("tweets", JSON.stringify(tweets);
 localStorage.setItem("tweets", JSON.stringify(tweets);
var tweets = JSON.parse(localStorage.getItem("tweets"));
 var tweets = JSON.parse(localStorage.getItem("tweets"));
Quota de 5 Mo
!   Pas de transactions
    Pas d'indexation
localStorage["tweets:1234"] = "Lorem ipsum...";
 localStorage["tweets:1234"] = "Lorem ipsum...";
localStorage["tweets:1235"] = "Nam mauris lorem...";
 localStorage["tweets:1235"] = "Nam mauris lorem...";
localStorage["tags"] = JSON.stringify(["Java", "Python",   
 localStorage["tags"] = JSON.stringify(["Java", "Python",   
                                      "Ruby", "PHP"]);
                                       "Ruby", "PHP"]);
localStorage["tags:Java"] = JSON.stringify([1234, 1235]);
 localStorage["tags:Java"] = JSON.stringify([1234, 1235]);
➔ 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é
>= 8   >= 3.5   >= 4.0    >= 4.0     >= 10.5




       >= 3.2    >= 2.1    >= 11.0
localStorage adapter
Backbone.sync = function(method, model, options) {
 Backbone.sync = function(method, model, options) {
  var resp;
   var resp;
  var store = model.localStorage || model.collection.localStorage;
   var store = model.localStorage || model.collection.localStorage;
  switch (method) {
   switch (method) {
    case "read":    resp = model.id ? store.find(model) : 
     case "read":    resp = model.id ? store.find(model) : 
                                             store.findAll(); 
                                              store.findAll(); 
         break;
          break;
    case "create":  resp = store.create(model);                                
     case "create":  resp = store.create(model);                                
         break;
          break;
    case "update":  resp = store.update(model);                            
     case "update":  resp = store.update(model);                            
         break;
          break;
    case "delete":  resp = store.destroy(model);                           
     case "delete":  resp = store.destroy(model);                           
         break;
          break;
  }
   }
  if (resp) {
   if (resp) {
    options.success(resp);
     options.success(resp);
  } else {
   } else {
    options.error("Record not found");
     options.error("Record not found");
  }
   }
};
 };
Petit intermède
        Vous connaissez Redis ?
BankersBox
var bb = new BankersBox(1);
 var bb = new BankersBox(1);
bb.set("foo", "bar");
 bb.set("foo", "bar");
bb.get("foo"); // returns "bar"
 bb.get("foo"); // returns "bar"
bb.set("count", 10);
 bb.set("count", 10);
bb.incr("count"); // sets "count" to 11, returns 11
 bb.incr("count"); // sets "count" to 11, returns 11
bb.incr("newcount"); // sets "newcount" to 1, returns 1
 bb.incr("newcount"); // sets "newcount" to 1, returns 1
bb.lpush("mylist", "hello");
 bb.lpush("mylist", "hello");
bb.lrange("mylist", 0, ­1); // returns ["hello"]
 bb.lrange("mylist", 0, ­1); // returns ["hello"]
bb.rpush("mylist", "world");
 bb.rpush("mylist", "world");
bb.lrange("mylist", 0, ­1); // returns ["hello", "world"]
 bb.lrange("mylist", 0, ­1); // returns ["hello", "world"]
bb.sadd("myset", "apple");
 bb.sadd("myset", "apple");
bb.sadd("myset", "oragne");
 bb.sadd("myset", "oragne");
IndexedDB
Préfixes, préfixes...
window.indexedDB = window.indexedDB || window.mozIndexedDB ||     
 window.indexedDB = window.indexedDB || window.mozIndexedDB ||     
                   window.webkitIndexedDB;
                    window.webkitIndexedDB;
window.IDBKeyRange = window.IDBKeyRange ||                        
 window.IDBKeyRange = window.IDBKeyRange ||                        
                     window.webkitIDBKeyRange;
                      window.webkitIDBKeyRange;
window.IDBTransaction = window.IDBTransaction ||                  
 window.IDBTransaction = window.IDBTransaction ||                  
                        window.webkitIDBTransaction;
                         window.webkitIDBTransaction;
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");
      }}
};
 };
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.");
      };
       };
};
 };
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);
      };
       };
};
 };
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();
          }}
      };
       };
};
 };
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
Index
var contacts = [
 var contacts = [
    { firstname: "John", lastname: "Doe", email: "jdoe@zz.com" },
     { firstname: "John", lastname: "Doe", email: "jdoe@zz.com" },
    { firstname: "Jane", lastname: "Doe", email: "jane@zz.com" },
     { firstname: "Jane", lastname: "Doe", email: "jane@zz.com" },
    { firstname: "Johnny", lastname: "Carson", email: "jca@zz.com" }
     { firstname: "Johnny", lastname: "Carson", email: "jca@zz.com" }
];
 ];
objectStore.createIndex("firstname", "firstname", { unique: false });
 objectStore.createIndex("firstname", "firstname", { unique: false });
objectStore.createIndex("lastname", "lastname", { unique: false });
 objectStore.createIndex("lastname", "lastname", { unique: false });
objectStore.createIndex("email", "email", { unique: true });
 objectStore.createIndex("email", "email", { unique: true });
Index
var contacts = [
 var contacts = [
    { firstname: "John", lastname: "Doe", email: "jdoe@zz.com" },
     { firstname: "John", lastname: "Doe", email: "jdoe@zz.com" },
    { firstname: "Jane", lastname: "Doe", email: "jane@zz.com" },
     { firstname: "Jane", lastname: "Doe", email: "jane@zz.com" },
    { firstname: "Johnny", lastname: "Carson", email: "jca@zz.com" }
     { firstname: "Johnny", lastname: "Carson", email: "jca@zz.com" }
];
 ];
var index = objectStore.index("lastname");
 var index = objectStore.index("lastname");
index.openCursor(IDBKeyRange.only("Doe")).onsuccess = function(e) {
 index.openCursor(IDBKeyRange.only("Doe")).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();
    }}
};
 };
var index = objectStore.index("firstname");
 var index = objectStore.index("firstname");
index.openCursor(IDBKeyRange.lowerbound("John")).onsuccess = 
 index.openCursor(IDBKeyRange.lowerbound("John")).onsuccess = 
function(e) {
 function(e) {
    ...
     ...
};
 };
>= 10 ?   >= 8.0   >= 16.0   ?       ?




            ?         ?          ?
Et pourquoi pas
Web SQL Database ?
X     X      >= 4.0    >= 3.1     >= 10.5




    >= 3.2    >= 2.1    >= 11.0
Le polyfill ultime ?

  Lawnchair
  ● localStorage
  ● indexedDB

  ● webkit­sqlite

  ● gears­sqlite

  ● ie­userdata

  ● backberry­persistent­store

  ● window­name
Etape 4
Développer une stratégie de
     synchronisation
L'exemple d'ActiveSync
POST /Microsoft­Server­ActiveSync?User=jdoe@zz.com&...
POST /Microsoft­Server­ActiveSync?User=jdoe@zz.com&...
     &Cmd=<Commande>
     &Cmd=<Commande>

Cmd=FolderSync&SyncKey=123456789
Cmd=FolderSync&SyncKey=123456789

{
{
    folders: [
    folders: [
       contacts: {
       contacts: {
          id: 1234,
          id: 1234,
          created: 0,
          created: 0,
          updated: 2,
          updated: 2,
          deleted: 1
          deleted: 1
       },
       },
       todos: {
       todos: {
          id: 5678,
          id: 5678,
          created: 5,
          created: 5,
          updated: 0,
          updated: 0,
          deleted: 2
          deleted: 2
       }
       }
    ]
    ]
}
}
Cmd=Sync&SyncKey=123456789&FolderId=5678
Cmd=Sync&SyncKey=123456789&FolderId=5678

{
{
   syncKey: 987654321,
   syncKey: 987654321,
   created: [
   created: [
      { id: 4321, label: "Acheter le pain" },
      { id: 4321, label: "Acheter le pain" },
      ...
      ...
   ],
   ],
   updated: [
   updated: [
      ...
      ...
   ],
   ],
   deleted: [
   deleted: [
      5678, 7890
      5678, 7890
   ]
   ]
}
}
Autres pistes

Mozilla Services
SyncML
Operational Transformation
 → ShareJS
Etape subsidiaire
    Le "push"
Polling
Client             Serveur




                             n secondes




                             n secondes
Long polling (COMET)
 Client       Serveur




                  Événement
                  côté serveur



                  Événement
                  côté serveur
WebSockets
Handshake
GET /resource name/ HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: /server/
Origin: /origin/
WebSocket­Protocol: /protocol/



HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket­Origin: /origin/
WebSocket­Location: /url/
WebSocket­Protocol: /subprotocol/
Serveur (avec node.js)

 var io = require('socket.io').listen(80);
 var io = require('socket.io').listen(80);

 io.sockets.on('connection', function (socket) {
 io.sockets.on('connection', function (socket) {
    socket.emit('news', { hello: 'world' });
     socket.emit('news', { hello: 'world' });
    socket.on('my other event', function (data) {
     socket.on('my other event', function (data) {
       console.log(data);
        console.log(data);
    });
     });
 });
 });



Client

 var socket = io.connect('http://localhost');
 var socket = io.connect('http://localhost');
 socket.on('news', function (data) {
 socket.on('news', function (data) {
    console.log(data);
     console.log(data);
    socket.emit('my other event', { my: 'data' });
     socket.emit('my other event', { my: 'data' });
 });
 });
>= 10 ?   >= 6.0   >= 14.0   >= 5.0     >= 11.0




          >= 4.2      ?       >= 11.0
Avec Socket.IO



>= 5.5   >= 3.0   >= 4.0    >= 3.0     >= 10.61




         >= 3.2    >= 2.1    >= 11.0
Server-Sent Events
HTTP traditionnel


GET /myAppStream


Content­Type: text/event­stream
if (window.EventSource) {
if (window.EventSource) {
  var source = new EventSource('myAppStream');
  var source = new EventSource('myAppStream');
} else {
} else {
  // fallback to something...
  // fallback to something...
}
}

source.addEventListener('message', function(e) {
source.addEventListener('message', function(e) {
  console.log(e.data);
  console.log(e.data);
}, false);
}, false);

source.addEventListener('open', function(e) {
source.addEventListener('open', function(e) {
  
  
}, false);
}, false);

source.addEventListener('error', function(e) {
source.addEventListener('error', function(e) {
  if (e.readyState == EventSource.CLOSED) {
  if (e.readyState == EventSource.CLOSED) {
    
    
  }
  }
}, false);
}, false);
Format des messages
data: Hello worldnn

Multi-ligne
data: Hellon
data: worldnn
JSON
data: {n
data: "msg": "Hello world",n
data: "id": 12345n
data: }nn
Format des messages
Utilisation des IDs
id: 12345n
data: {"user": "goldo", "msg": "Hello !"}nn



Utilisation des events
data: {"msg": "Hello !"}nn
event: loginn
data: {"user": "goldo"}nn
event: updaten
data: {"user": "goldo", "status": "away"}nn
Avantages

Reconnexion automatique
Ids
Events
Questions / réponses

Mais conteúdo relacionado

Mais procurados

Puppet Conf 2012 - Managing Network Devices with Puppet
Puppet Conf 2012 - Managing Network Devices with PuppetPuppet Conf 2012 - Managing Network Devices with Puppet
Puppet Conf 2012 - Managing Network Devices with Puppet
Nan Liu
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
DjangoCon2008
 
WebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleWebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at Google
Robert Nyman
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
Skills Matter
 
深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVC
Jace Ju
 

Mais procurados (20)

JavaFX – 10 things I love about you
JavaFX – 10 things I love about youJavaFX – 10 things I love about you
JavaFX – 10 things I love about you
 
Spring 4 - A&BP CC
Spring 4 - A&BP CCSpring 4 - A&BP CC
Spring 4 - A&BP CC
 
Puppet Conf 2012 - Managing Network Devices with Puppet
Puppet Conf 2012 - Managing Network Devices with PuppetPuppet Conf 2012 - Managing Network Devices with Puppet
Puppet Conf 2012 - Managing Network Devices with Puppet
 
Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Library
 
企业级软件的组件化和动态化开发实践
企业级软件的组件化和动态化开发实践企业级软件的组件化和动态化开发实践
企业级软件的组件化和动态化开发实践
 
Testing Microservices with a Citrus twist
Testing Microservices with a Citrus twistTesting Microservices with a Citrus twist
Testing Microservices with a Citrus twist
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
 
The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
 
Dan Webb Presentation
Dan Webb PresentationDan Webb Presentation
Dan Webb Presentation
 
WCLA12 JavaScript
WCLA12 JavaScriptWCLA12 JavaScript
WCLA12 JavaScript
 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3
 
Performance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScriptPerformance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScript
 
Cake Php 1.2 (Ocphp)
Cake Php 1.2 (Ocphp)Cake Php 1.2 (Ocphp)
Cake Php 1.2 (Ocphp)
 
WebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleWebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at Google
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Phone gap 12 things you should know
Phone gap 12 things you should knowPhone gap 12 things you should know
Phone gap 12 things you should know
 
Rails vs Web2py
Rails vs Web2pyRails vs Web2py
Rails vs Web2py
 
How containers helped a SaaS startup be developed and go live
How containers helped a SaaS startup be developed and go liveHow containers helped a SaaS startup be developed and go live
How containers helped a SaaS startup be developed and go live
 
深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVC
 
Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 

Semelhante a Html5 : stockage local & synchronisation

Offline Application Cache
Offline Application CacheOffline Application Cache
Offline Application Cache
Jonathan Stark
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?
Remy Sharp
 
Html5 and beyond the next generation of mobile web applications - Touch Tou...
Html5 and beyond   the next generation of mobile web applications - Touch Tou...Html5 and beyond   the next generation of mobile web applications - Touch Tou...
Html5 and beyond the next generation of mobile web applications - Touch Tou...
RIA RUI Society
 
Web app and more
Web app and moreWeb app and more
Web app and more
faming su
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 
Firefox OS workshop, JSFoo, India
Firefox OS workshop, JSFoo, IndiaFirefox OS workshop, JSFoo, India
Firefox OS workshop, JSFoo, India
Robert Nyman
 
Taking Web Apps Offline
Taking Web Apps OfflineTaking Web Apps Offline
Taking Web Apps Offline
Pedro Morais
 
PhoneGap:你应该知道的12件事
PhoneGap:你应该知道的12件事PhoneGap:你应该知道的12件事
PhoneGap:你应该知道的12件事
longfei.dong
 
Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
 	Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W... 	Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
Robert Nyman
 
WebAPIs & Apps - Mozilla London
WebAPIs & Apps - Mozilla LondonWebAPIs & Apps - Mozilla London
WebAPIs & Apps - Mozilla London
Robert Nyman
 

Semelhante a Html5 : stockage local & synchronisation (20)

Offline Application Cache
Offline Application CacheOffline Application Cache
Offline Application Cache
 
Dave Orchard - Offline Web Apps with HTML5
Dave Orchard - Offline Web Apps with HTML5Dave Orchard - Offline Web Apps with HTML5
Dave Orchard - Offline Web Apps with HTML5
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?
 
Persistent mobile JavaScript
Persistent mobile JavaScriptPersistent mobile JavaScript
Persistent mobile JavaScript
 
HTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & socketsHTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & sockets
 
Html5 and beyond the next generation of mobile web applications - Touch Tou...
Html5 and beyond   the next generation of mobile web applications - Touch Tou...Html5 and beyond   the next generation of mobile web applications - Touch Tou...
Html5 and beyond the next generation of mobile web applications - Touch Tou...
 
Web Apps and more
Web Apps and moreWeb Apps and more
Web Apps and more
 
Web app and more
Web app and moreWeb app and more
Web app and more
 
"Progressive Web Apps" by Riza Fahmi (Hacktiv8)
"Progressive Web Apps" by Riza Fahmi	(Hacktiv8)"Progressive Web Apps" by Riza Fahmi	(Hacktiv8)
"Progressive Web Apps" by Riza Fahmi (Hacktiv8)
 
Progressive Web Apps. What, why and how
Progressive Web Apps. What, why and howProgressive Web Apps. What, why and how
Progressive Web Apps. What, why and how
 
Pushing the Web: Interesting things to Know
Pushing the Web: Interesting things to KnowPushing the Web: Interesting things to Know
Pushing the Web: Interesting things to Know
 
HTML5와 모바일
HTML5와 모바일HTML5와 모바일
HTML5와 모바일
 
JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011JavaServer Faces 2.0 - JavaOne India 2011
JavaServer Faces 2.0 - JavaOne India 2011
 
HTML5 on Mobile
HTML5 on MobileHTML5 on Mobile
HTML5 on Mobile
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Firefox OS workshop, JSFoo, India
Firefox OS workshop, JSFoo, IndiaFirefox OS workshop, JSFoo, India
Firefox OS workshop, JSFoo, India
 
Taking Web Apps Offline
Taking Web Apps OfflineTaking Web Apps Offline
Taking Web Apps Offline
 
PhoneGap:你应该知道的12件事
PhoneGap:你应该知道的12件事PhoneGap:你应该知道的12件事
PhoneGap:你应该知道的12件事
 
Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
 	Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W... 	Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
Bringing the open web and APIs to mobile devices with Firefox OS - Whisky W...
 
WebAPIs & Apps - Mozilla London
WebAPIs & Apps - Mozilla LondonWebAPIs & Apps - Mozilla London
WebAPIs & Apps - Mozilla London
 

Mais de goldoraf (7)

jQuery sans jQuery
jQuery sans jQueryjQuery sans jQuery
jQuery sans jQuery
 
Tester son JS, c'est possible !
Tester son JS, c'est possible !Tester son JS, c'est possible !
Tester son JS, c'est possible !
 
Ember.js
Ember.jsEmber.js
Ember.js
 
Services web RESTful
Services web RESTfulServices web RESTful
Services web RESTful
 
Git ou le renouveau du contrôle de version
Git ou le renouveau du contrôle de versionGit ou le renouveau du contrôle de version
Git ou le renouveau du contrôle de version
 
Rich Desktop Applications
Rich Desktop ApplicationsRich Desktop Applications
Rich Desktop Applications
 
Forum PHP 2007 - Methodes Agiles
Forum PHP 2007 - Methodes AgilesForum PHP 2007 - Methodes Agiles
Forum PHP 2007 - Methodes Agiles
 

Último

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 

Último (20)

Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 

Html5 : stockage local & synchronisation

Notas do Editor

  1. La difficulté de la tâche dépend de l&apos;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&apos;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 &amp;quot; simple &amp;quot; En fonction de l&apos;application, on choisira une conception &amp;quot; modale &amp;quot; (l&apos;user choisit explicitement de basculer en offline, d&apos;où un chargement local initial des données), notamment si l&apos;appli présente des données hors de contrôle de l&apos;user (ex : feedreader), ou &amp;quot; modeless &amp;quot; (ex : webmail, gestion de tâches...) Dans tous les cas, supporter une utilisation offline complexifie l&apos;appli, il convient donc de s&apos;assurer que ce type d&apos;utilisation est pleinement justifié
  2. Le cache d&apos;une appli est limité à 5 Mo (à checker) Diffère de la mise en cache &amp;quot; classique &amp;quot; des navigateurs, qui est plus volatile
  3. Une fois que les ressources sont mises en cache, le cache n&apos;est mis à jour que si le manifeste change
  4. Autre pb : le navigateur n&apos;essaiera même pas de charger toute ressource qui n&apos;est pas mentionnée dans le manifeste, les URIs type API et autre doivent donc être mentionnées dans la section NETWORK
  5. On détecte l&apos;event &apos;updateready&apos; qui signale une mise à jour du manifeste et donc une MAJ potentielle des ressources pour en avertir l&apos;user et rafraîchir la page, donnant ainsi à l&apos;user l&apos;accès aux nouvelles ressources
  6. Plus facile à dire qu&apos;à faire (tout dépend de l&apos;appli) : l&apos;idée est dans un premier temps d&apos;encapsuler les appels XHR dispersés dans l&apos;appli dans un module type Repository : l&apos;appli ne parle plus directement à un serveur mais à un objet dépôt de données qui, pour l&apos;instant, fait des appels XHR
  7. Maintenant que l&apos;application est découplée du réseau, nous pouvons faire en sorte que notre objet &amp;quot; dépôt &amp;quot; persiste localement les données chargées depuis le serveur
  8. API permettant de lire/écrire des reps et fichiers dans une portion &amp;quot; sandboxée &amp;quot;, par application, du FS Uniquement pour Chrome &gt;= 13.0 pour toutes les fonctionnalités Tous les objets sont préfixés par webkit
  9. 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&apos;autorisation à l&apos;utilisateur Il existe une API pour checker le statut et l&apos;utilisation du quota
  10. SessionStorage supprime les données lorsque le navigateur est fermé
  11. 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&apos;accès concurrent (race condition) si l&apos;appli est utilisé dans 2 onglets par exemple
  12. Si le support d&apos;IE 7 est requis, il existe un polyfill simple qui va stocker les données dans le cookie
  13. 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)
  14. 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&apos;on ne referme pas la connexion à chaque event mais où on envoie une réponse en plusieurs fois ; pb : mal supporté par certains proxys
  15. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  16. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  17. Socket.IO utilise le meilleur moyen à sa dispo : - websockets - Flash socket - long polling - Ajax streaming - forever iframe - JSONP polling
  18. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  19. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  20. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  21. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé
  22. Connexion bidirectionnelle full-duplex à travers une socket TCP Plusieurs connexions possibles sur le même port S&apos;efforce de traverser proxys et firewall Protocole RFCisé