2013-05-10 50 views
1

所以,我正在開發一個JavaScript + API論壇軟件。我的觀點是,您可以在離線時閱讀論壇 - 這涉及HTML5的離線存儲。特別是,我想使用IndexedDB,因爲它似乎是未來最有希望的。我已經獲得了一個很好的服務/工廠來獲取/臨時存儲數據,但IDDB被大量破壞。有沒有人有關於如何解決這個問題的建議?有沒有好的方式來使用Angular.js和索引數據庫?

編輯另外,對於任何想要託管版本的人,這裏是cloud9

var angular = angular || {}; 
(function(w){ 
    w.localStorage = w.localStorage||{}; 
    w.indexedDB = w.indexedDB || w.mozIndexedDB || w.webkitIndexedDB || w.msIndexedDB || null; 
    w.IDBTransaction = w.IDBTransaction || w.webkitIDBTransaction || w.msIDBTransaction || null; 
    w.IDBKeyRange = w.IDBKeyRange || w.webkitIDBKeyRange || w.msIDBKeyRange || null; 
})(this); 

angular.module("JSForumServices",[],function($provide){ 
    $provide.factory('ForumStorage',(function(){ 
     var service = { 
      post:null, 
      thread:null, 
      board:null, 
      cache:{}, 
      pending:{} 
     }; 
     var fetch = (function(baseFunction,path,callback){ 
      if(path in service.pending) 
       return service.pending[path]; 
      var r=baseFunction(); 
      service.pending[path] = r; 
      var ajaxRequest = new XMLHttpRequest(); 
      var cancelled = false; 
      var dateRegex = 
       /^(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s+)?(0[1-9]|[1-2]?[0-9]|3[01])\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(19[0-9]{2}|[2-9][0-9]{3})\s+(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?\s+([-\+][0-9]{2}[0-5][0-9]|(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z]))(\s+|\(([^\(\)]+|\\\(|\\\))*\))*$/; 
      ajaxRequest.onreadystatechange = (function(){ 
       var readyState = ajaxRequest.readyState; 
       if(readyState==4&&(!cancelled)){ 
        // Store the copy locally! 
        // Also, initiate the callback. 
        // This way if the storage fails, 
        // The application continues to work 
        // As expected. 
        var data = JSON.parse(ajaxRequest.responseText); 
        for(var k in data) 
         r[k] = data[k]; 
        service.cache[path]={obj:r,modified:new Date()}; 
        delete service.pending[path]; 
        callback(r); 
       } 
       else if((path in service.cache)&&readyState>=2){ 
        var oldDate = service.cache[path].modified; 
        console.log("Cache'd copy for",path,"exists.",oldDate.toString()); 
        var isMoreRecent = false;//Is the server-copy more recent? 
        var serverModifiedString = ajaxRequest.getResponseHeader("Last-Modified"); 
        console.log(serverModifiedString); 
        var match = dateRegex.exec(serverModifiedString); 
        var serverModified = new Date(); 
        serverModified.setDate(parseInt(match[2],10)); 
        serverModified.setMonth({ 
         "jan":0, 
         "feb":1, 
         "mar":2, 
         "apr":3, 
         "may":4, 
         "jun":5, 
         "jul":6, 
         "aug":7, 
         "sep":8, 
         "oct":9, 
         "nov":10, 
         "dec":11 
        }[match[3].toLowerCase()]); 
        serverModified.setYear(parseInt(match[4],10)); 
        serverModified.setHours(parseInt(match[5],10)); 
        serverModified.setMinutes(parseInt(match[6],10)); 
        serverModified.setMilliseconds(parseInt(match[7],10)); 
        isMoreRecent = serverModified > oldDate; 
        if(!isMoreRecent&&(path in service.pending)){//sometimes this code may be slower than network speeds? Just to be safe, I guess. 
         cancelled=true; 
         var oldObject = service.cache[path].obj; 
         for(var key in oldObject) 
          r[key]=oldObject[key]; 
         console.log("using a cache'd value.",r); 
         callback(r); 
         delete service.pending[path]; 
         ajaxRequest.abort();//No need to waste more bandwidth! 
        } 
       } 
      }); 
      ajaxRequest.open("GET",path,true); 
      ajaxRequest.send(); 
      return r; 
     }); 
     var ObjectFetch = (function(base,constr){ 
      var ret = (function(id,cb){ 
       cb = cb||(function(){}); 
       return fetch(constr,base+id+".json",cb); 
      }); 
      return ret; 
     }); 
     service.post = ObjectFetch("./post/",(function(){ 
      return { 
       id:"???", 
       author:"???", 
       content:"", 
       date:"" 
      }; 
     })); 
     service.thread = ObjectFetch("./thread/",(function(){ 
      return { 
       id:"???", 
       title:"???", 
       posts:[], 
       tags:"" 
      }; 
     })); 
     service.board = ObjectFetch("./board/",(function(){ 
      return { 
       id:"???", 
       title:"???", 
       threads:[], 
       tags:"" 
      }; 
     })); 
     service.forum = ObjectFetch("./",(function(){ 
      return { 
       name:"Javascript Forum Software.", 
       boards:[] 
      }; 
     })); 
     if(window.indexedDB!==null){ 
      var postFetch = service.post; 
      var threadFetch = service.thread; 
      var boardFetch = service.board; 
      (function(dbengine){ 
       var boardsLoaded = false; 
       var threadsLoaded = false; 
       var postsLoaded = false; 
       var req = dbengine.open("forum",1); 
       req.onupgradeneeded = (function(e){ 
        var db = e.target.result; 
        db.createObjectStore("post",{ 
         keyPath:"id" 
        }); 
        db.createObjectStore("thread",{ 
         keyPath:"id" 
        }); 
        db.createObjectStore("board",{ 
         keyPath:"id" 
        }); 
       }); 
       req.onsuccess = (function(e){ 
        service.database = e.target.result; 
        var loadData = service.database.transaction([ 
         'board', 
         'thread', 
         'post'],'readwrite'); 
        loadData.onsuccess = (function(ee){ 
         var transaction = ee.target.result; 
         transaction.objectStore("board").openCursor().onsuccess=(function(e){ 
          var cursor = e.target.result; 
          if(cursor===null){ 
           boardsLoaded = true; 
           return; 
          } 
          var id = cursor.key; 
          var obj = cursor.value; 
          var lastModified = new Date(); 
          if("lastModified" in obj){ 
           lastModified = obj.lastModified; 
          } 
          service.cache["./board/"+id.toString().toLowerCase()+".json"]={ 
           obj:obj, 
           modified:lastModified 
          }; 
         }); 
         transaction.objectStore("thread").openCursor().onsuccess=(function(e){ 
          var cursor = e.target.result; 
          if(cursor===null){ 
           threadsLoaded = true; 
           return; 
          } 
          var id = cursor.key; 
          var obj = cursor.value; 
          var lastModified = new Date(); 
          if("lastModified" in obj){ 
           lastModified = obj.lastModified; 
          } 
          service.cache["./thread/"+id.toString().toLowerCase()+".json"]={ 
           obj:obj, 
           modified:lastModified 
          }; 
         }); 
         transaction.objectStore("post").openCursor().onsuccess=(function(e){ 
          var cursor = e.target.result; 
          if(cursor===null){ 
           postsLoaded = true; 
           return; 
          } 
          var id = cursor.key; 
          var obj = cursor.value; 
          var lastModified = new Date(); 
          if("lastModified" in obj){ 
           lastModified = obj.lastModified; 
          } 
          service.cache["./post/"+id.toString().toLowerCase()+".json"]={ 
           obj:obj, 
           modified:lastModified 
          }; 
         }); 
         service.post = (function(id,cb){ 
          console.log("DDDDDAFF"); 
          var trans = service.database.transaction(["post"],"readwrite"); 
          trans.onsuccess = (function(e){ 
           var req = e.target.result.objectStore("post").get(id); 
           req.onsuccess = (function(ee){ 
            cb(req.result); 
           }); 
           req.onerror = (function(ee){ 
            console.log("HAAAA?!"); 
            postFetch(id,(function(post){ 
             e.target.result.objcetStore.save(post); 
             cb(post); 
            })); 
           }); 
          }); 
          trans.onerror = (function(e){ 
           console.log("Error with IDDB:",e); 
           threadFetch(id,cb); 
          }); 
         }); 
         service.thread = (function(id,cb){ 
          var trans = service.database.transaction(["thread"],"readwrite"); 
          trans.onsuccess = (function(e){ 
           var req = e.target.result.objectStore("thread").get(id); 
           req.onsuccess = (function(ee){ 
            cb(req.result); 
           }); 
           req.onerror = (function(ee){ 
            threadFetch(id,(function(post){ 
             e.target.result.objcetStore.save(post); 
             cb(post); 
            })); 
           }); 
          }); 
          trans.onerror = (function(e){ 
           console.log("Error with IDDB:",e); 
           postFetch(id,cb); 
          }); 
         }); 
         service.board = (function(id,cb){ 
          var trans = service.database.transaction(["board"],"readwrite"); 
          trans.onsuccess = (function(e){ 
           var req = e.target.result.objectStore("board").get(id); 
           req.onsuccess = (function(ee){ 
            cb(req.result); 
           }); 
           req.onerror = (function(ee){ 
            boardFetch(id,(function(post){ 
             e.target.result.objcetStore.save(post); 
             cb(post); 
            })); 
           }); 
          }); 
          trans.onerror = (function(e){ 
           console.log("Error with IDDB:",e); 
           boardFetch(id,cb); 
          }); 
         }); 
        }); 
       }); 
      })(window.indexedDB); 
     } 
     return service; 
    })); 
}); 

angular.module('JSForum',["JSForumServices"]).config(
    ['$routeProvider', 
    function($routeProvider){ 
    $routeProvider.when('/',{ 
     templateUrl:"forum.html", 
     controller:ForumController 
    }); 
    $routeProvider.when('/board/:id',{ 
     templateUrl:"board.html", 
     controller:BoardController 
    }); 
    $routeProvider.when('/thread/:id',{ 
     templateUrl:"thread.html", 
     controller:ThreadController 
    }); 
    $routeProvider.otherwise({redirectTo:"/"}); 
}]); 

function ThreadController($scope,$routeParams,ForumStorage){ 
    $scope.id = $routeParams.id.toString().toLowerCase(); 
    $scope.thread = null; 
    ForumStorage.thread($scope.id,(function(thread){ 
     $scope.thread = thread; 
     $scope.$apply(); 
     var callback = (function(p){ 
      return (function(post){ 
       $scope.thread.posts[p] = post; 
       $scope.$apply(); 
      }); 
     }); 
     for(var i=0;i<thread.posts.length;i++) 
      if(typeof(thread.posts[i].id) == 'undefined') 
       ForumStorage.post(thread.posts[i],callback(i)); 
     $scope.$apply(); 
    })); 
} 

function BoardController($scope,$routeParams,ForumStorage){ 
    $scope.id = $routeParams.id.toString().toLowerCase(); 
    $scope.board = null; 
    ForumStorage.board($scope.id,(function(board){ 
     var callback = (function(p){ 
      return (function(thread){ 
       $scope.board.threads[p] = thread; 
       $scope.$apply(); 
      }); 
     }); 
     $scope.board = board; 
     console.log("Using board:",$scope.board); 
     for(var i=0;i<board.threads.length;i++) 
      if(typeof(board.threads[i].id)=='undefined') 
       ForumStorage.thread(board.threads[i],callback(i)); 
     $scope.$apply(); 
    })); 
} 

function ForumController($scope,ForumStorage){ 
    $scope.name = localStorage.forumName||"Forum"; 
    $scope.boards = []; 
    ForumStorage.forum("forum",(function(forum){ 
     document.title = $scope.name = localStorage.forumName = forum.name; 
     $scope.boards = forum.boards; 
     var callback=(function(p){ 
      return (function(o){ 
       $scope.boards[p] = o; 
       $scope.$apply(); 
      }); 
     }); 
     for(var i=0;i<$scope.boards.length;i++){ 
      if(typeof($scope.boards[i].id) == 'undefined') 
       ForumStorage.board(forum.boards[i],callback(i)); 
     } 
     $scope.$apply(); 
    })); 
} 
+0

你可以站起來工作的小提琴或詳細說明你的意思是'重大損壞'?這是很多需要閱讀的代碼。 – Langdon 2013-05-10 19:35:21

+0

我的意思是它還沒有做任何事情,當它做到時,它的行爲並不一致。 無論如何,[這裏](https://c9.io/tyler-elric/phoenix/workspace/index.html)是一個運行它的Cloud9。 – 2013-05-10 21:03:13

回答

-1

如果你的後端是谷歌雲存儲,你可以使用我的開源數據庫庫http://dev.yathit.com/api-reference/ydn-db/storage.html它在IndexedDB的高速緩存,並且堅持到BLOB存儲。論壇帖子URI路徑作爲記錄的主鍵。 LastModified頭部值持久保存到IndexedDB中並用於有條件的HTTP請求。由於blob存儲只能按鍵(URI路徑)的升序查詢,所以會生成論壇帖子URI路徑,以便最後的帖子最小。通過這種方式,我們可以通過提供最小的已知密鑰marker來查詢新帖子。

一個例子可以在https://bitbucket.org/ytkyaw/ydn-auth/src/master/examples/note-app/note-app.js找到(不是論壇,而是一個簡單的筆記應用程序)。您需要一個生成signed url來發布新記錄的後端服務器。

+0

我喜歡它! IndexedDB緩存是否容易拔出和重用,還是相當根深蒂固? – 2013-05-12 19:19:03

+0

我不確定你的問題。緩存是可選的。 – 2013-05-13 01:08:28

+0

:l ... OOP。 ??? – 2013-05-14 21:37:47

相關問題