单页/手机应用中的

本地存储与同步

Merlin Ran / @MerlinRan

merlinran@gmail.com

离线不是异常

  • 隧道
  • 野外
  • 网络不稳定
  • 服务器维护
  • ……

缓存

应用和资源

  • 浏览器缓存
  • Application Cache

数据

  • localStorage
  • IndexedDB
  • Web SQL
  • Cordova Plugin

本地修改

  • 微博/QQ/微博
  • Jianshu.io

自动同步

PouchDB


var db = new PouchDB('dbname');

db.put({
_id: 'dave@gmail.com',
name: 'David',
age: 67
});

db.changes().on('change', function() {
console.log('Ch-Ch-Changes');
});

db.replicate.to('http://example.com/mydb');
            

多终端同步

  • Tower.im
  • Derby/Racer
  • Meteor

No Backend

  • Firebase
  • Deployd
  • ……

//CREATE A FIREBASE
var fb = new Firebase("https://YOUR.firebaseio.com/");

//SAVE DATA
fb.set({ name: "Alex Wolfe" });

//LISTEN FOR REALTIME CHANGES
fb.on("value", function(data) {
var name = data.val() ? data.val().name : "";
alert("My name is " + name);
});
            

数据冲突

加锁

解决算法

  • Differential Synchronization
  • diff

  • Operational Transformation
  • log

基于Timestamp

本地修改时间 or 服务器时间?

Offline First

Hoodie.js


hoodie = new Hoodie();
hoodie.store.findAll().done(function(pets) {
$scope.pets = pets;
});

hoodie.store.on('change', function (eventName, changedObject) {
$scope.$apply(refresh);
});
            

$scope.addPet = function() {
hoodie.store.add('pets', {name: $scope.newPetName})
.done(function(newPet) {
// do nothing
});
};

$scope.removePet = function(index) {
var pet = $scope.pets[index];
hoodie.store.remove('pets', pet.id)
.done(function() {
// do nothing
});
};
            

hoodieArray.bind($scope, 'pets', 'pets');

// another controller
hoodie.store.on('change:pets', function (eventName, changedObject) {
  // ...
});
            

Let's Discuss!

&

https://speakerdeck.com/espylaub/offline-first-web-apps