Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/414.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于实时和离线web应用的Javascript库_Javascript - Fatal编程技术网

用于实时和离线web应用的Javascript库

用于实时和离线web应用的Javascript库,javascript,Javascript,我有一个带有RESTAPI的后端服务器。在前端,我使用Angular.js。为了处理实时部分,我想使用第三方服务,如Pusher 我正在寻找一个简单的库,可以处理前端mvc部分的m。更具体地说,我想要一个模型接口,它将抽象掉离线和实时方面的复杂性 例如,从角度来看,我希望订阅我的模型,并在模型更改时收到通知。我还希望有一个.save方法来处理与服务器和其他客户端的同步 该图书馆应: 脱机工作:它将数据保存在本地存储中,并在恢复联机时与服务器同步 侦听实时更改,更新其模型并将更改传播给侦听器 使用

我有一个带有RESTAPI的后端服务器。在前端,我使用Angular.js。为了处理实时部分,我想使用第三方服务,如Pusher

我正在寻找一个简单的库,可以处理前端mvc部分的m。更具体地说,我想要一个模型接口,它将抽象掉离线和实时方面的复杂性

例如,从角度来看,我希望订阅我的模型,并在模型更改时收到通知。我还希望有一个.save方法来处理与服务器和其他客户端的同步

该图书馆应:

脱机工作:它将数据保存在本地存储中,并在恢复联机时与服务器同步

侦听实时更改,更新其模型并将更改传播给侦听器

使用标准的REST接口可以很好地工作

因此,作为一个快速的伪代码示例,在Angular中,我想做:

my_controller = function($scope) {
  User.find_all(function(users) {
    $scope.users = users;
  });
}
用户是模型的抽象。。当它得到实时更新时,my$scope.users应该相应地更改

$scope.users[0].set('name', 'testing)
这将把模型保存到服务器上。或者,如果脱机,则应将其保存在本地,并在稍后恢复联机时进行同步

我知道有一些在线服务试图实现这一目标,比如Firebase和kinvey。这些工具的问题在于,它只提供托管解决方案。我需要控制REST服务器和数据库。因此,基本上,我正在寻找一个Firebase库-没有所有的身份验证和授权-可以与REST服务器和pubsub第三方一起工作


谢谢

我认为你应该开始研究HTML5 WebSocket:

它允许服务器和客户端、客户端拉和服务器推之间的双向通信


然后看看signar,HTML5 WebSockets的asp.net实现:

这个答案有点长,但我还没有发布它

function monitor(obj, callBack){


var api={
        patch: patchObjectWithDiff, 
        init: init, 
        resolve: resolve, 
        snapshot: snapshot, 
        diff: diff, 
        update: changeMonitor 
   };



function merge2(o, ob) {
     for (var z in ob) {
        if (ob.hasOwnProperty(z)) {
           if(typeof ob[z]=="object"){ 
                if(ob[z]==null){
                    delete o[z];
                }else{
                    merge2( o[z] || {},  ob[z]);
                }

            }else{
                 o[z] = ob[z];
            }

        }
    }
    return o;
}






function snapshot(obj) { 
    var out = [];
    function merge3(ob, path) {
        path = path || [];
                var tp;
        for(var z in ob) {
            if(ob.hasOwnProperty(z)) {
                if(ob[z] && typeof ob[z] == "object" && [Date, RegExp].indexOf(ob[z].constructor) == -1) {

                                        tp=path.concat(z);
                    out.push({
                                                path:  tp.join("`"),
                                                path2:  tp,
                                                dt:  "set",
                                                date:  +new Date,
                                                v: Array.isArray(ob[z]) ? "[]" : "{}"
                                        });

                    merge3(ob[z], path.concat(z));
                } else {
                                        tp=path.concat(z);
                    out.push({
                                                path:  tp.join("`"),
                                                path2:  tp,
                                                type:  "set",
                                                dt:  +new Date,
                                                v: JSON.stringify(ob[z]) 
                                        });
                }
            }
        }
    }

    merge3(obj);
    return out;
};



function diff(d1, d2){

  var out=d2.filter(function(a,b,c){
     var ov=JSON.stringify(a.v);
     return d1.some(function(aa,bb){ return aa.path==a.path && JSON.stringify(aa.v) != ov;  });
  }),

  // find deletions
  dels=d1.filter(function(a,b,c){
     return !d2.some(function(aa,bb){ if(aa.path==a.path ){  return true; };  });
  }),

  allPaths=dels.map(function(a){return a.path}).sort(),

  dels2=dels.filter(function eliminateUnneededSubBranches(a){

        var pos=allPaths.indexOf( a.path2.slice(0,-1).join("`") );

        return pos==-1 || pos >= allPaths.indexOf(a.path);

  }).map(function(a){a.type="del"; delete a.v; return a;});


  [].push.apply(out, dels2);


 //find inserts


var outNew=d2.filter(function(a,b,c){
     var ov=JSON.stringify(a.v);
     return !d1.some(function(aa,bb){ return aa.path==a.path  });
  });

 [].push.apply(out, outNew);



  return out.map(function(a){
       var x= {
         dt: a.dt,
         k: a.path2
       };

       if(a.hasOwnProperty("v")){ x.v=a.v; }

       return x;

            a.k=a.path2; 
            delete a.path; 
            delete a.path2; 
            delete a.type;
      return a;
  });
}



function resolve(path, object){
  var tob=object;
  path.map(function(a){ return (tob=tob[a])||tob; })
 return tob;
}








function patchObjectWithDiff(diff, object){

  diff.forEach(function(a,b,c){
       var p= resolve(a.k.slice(0,-1), object), 
           k= a.k.slice(-1)[0];

       if(a.hasOwnProperty("v")){ //set:
              p[k]=JSON.parse(a.v);
             if(String(p[k]).match(/Z$/)){ p[k]=new Date(''+p[k]) || p[k]; }
        }else{ // del:
           if(Array.isArray(p)){ p.splice(k,1); }else{ delete p[k]; }
       }
  });

   return object;
}











    var init=snapshot(JSON.parse(JSON.stringify(obj))),
          id=Math.random()+ Number(new Date());


    var init=snapshot(obj);

    function changeMonitor(){
        var thisTime=snapshot(obj),
               diffs=diff(init, thisTime);
        if(diffs.length){  
            api.diffs=diffs;
            (callBack||console.log.bind(console))("objectUpdate", diffs );
            init=thisTime;
        }//end if change?
    }

    setInterval(changeMonitor, 2500);

 return api;

}
演示/示例用法:

var obj={a:1, b:[1,2,3], c: false}; // a model object
var dupe=JSON.parse(JSON.stringify(obj)); // a cheap clone of the data for demo use

//subscribe this object to updates    
var mon=monitor(obj, function(type, changes){console.log(type,  changes); });

// make some changes to the object:
obj.e="cool!";
obj.b.push(5);
obj.a=7;

// manually call update instead of waiting for the bundler:
//  (this is needed for this demo so we can reconcile the changes in sync and view the output)
mon.update();

// now apply stored changes to the clone of the orig data:
var updatedDupe= mon.patch(mon.diffs, dupe);

// use a cheap and easy but not production-reliable to compare the objects:
JSON.stringify(updatedDupe)==JSON.stringify(obj); // should be true
在chrome和firefox中测试

请注意,此特定演示对JSON的使用取决于运气和一致的密钥顺序,而JS规范并不保证这一点。密钥顺序并不重要,但它可能会导致JSON.stringify==比较失败,即使对象的属性确实是同步的。这只是为了得到一个正确/错误的答案,如果它有效,不要打我

您可以给它一个自定义回调senddiff,{diffs:mon.diffs}当更改发生时,使用pusher等人提供的订阅事件,如ondiff,function{mon.patch.diffs,obj;};在MVC中应用更改并触发视图更新

我将让您根据需要在本地存储和在线/离线存储中工作,完成这一步后应该会非常容易

更改列表中的所有差异都带有三个键:

  {"dt":1392348959730,"k":["b","3"],"v":"5"}
dt: a timestamp of when the change was discovered
k: the key path where the change was detected
v: what the discovered changed value is as of dt
这个脚本很热门,我还没有时间编写适当的文档,但我认为它可能会有帮助,或者至少会激发出一个适合您的解决方案