Storage

283 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
283
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Storage

  1. 1. HTML5 开发Web,MobileWeb & Apps范圣刚安博中程在线
  2. 2. STORAGE
  3. 3. Cookie的问题和本地存储的需求安博中程在线cookie可以用来持久化存储少量的数据,但是它具有一些问题:我们真正需要的是:·每一次HTTP Request都会发送cookie信息,会使Web application变慢。每一次HTTP Request中发送的cookie信息都以未加密方式在网上传输,具有安全性问题。cookie信息量最大不能超过4KB,对于实用性而言太小了。····足够大的存储空间存储在客户端在页面刷新的情况下也能将存储的数据持久化存储的数据不会每次都传输给服务器····3/34
  4. 4. Web StorageWeb Storage 可以让Web页面在客户端浏览器中以键值对的形式在本地存储数据。原先是HTML5规范的一部分,后来被抽离出来形成了单独的一份标准。某些浏览器厂商又把它叫做“本地存储”或者“DOM存储”。特性检测也可以使用Modernizr库进行检测安博中程在线function supports_html5_webstorage() {return (localStorage in window) && window[localStorage] != null;}JAVASCRIPTif (Modernizr.localStorage) {// window.localStorage 可用!} else {// 没有本地HTML5存储支持}JAVASCRIPT4/34
  5. 5. 使用 HTML5 存储HTML5 是基于key/value形式的。存储和检索数据都通过指定的key:安博中程在线interfaceStorage{getteranygetItem(inDOMStringkey);settercreatorvoidsetItem(inDOMStringkey,inanydata);deletervoidremoveItem(inDOMStringkey);voidclear();readonlyattributeunsignedlonglength;getterDOMStringkey(inunsignedlongindex);}...localStorage.setItem("username","tom");vartom=localStorage.getItem("username");localStorage["age"]=30;varage=localStorage.getItem(age);JAVASCRIPT5/34
  6. 6. storage事件通过捕获storage事件可以跟踪存储区的改动, 任何时候调用setItem(), removeItem()或者clear()方法时,如果真的发生了数据改动,都会在window对象上触发storage事件。(只要支持localStorage对象就一定支持storage事件)handle_storage()回调函数被调用时,会传入一个StorageEvent对象作为参数,IE下面的事件对象存储在window.event上:安博中程在线if (window.addEventListener) {window.addEventListener(storage, handle_storage, false);} else {window.attachEvent(onstorage, handle_storage);}JAVASCRIPTfunction handle_storage(e) {if (!e) { e = window.event; }}JAVASCRIPT6/34
  7. 7. StorageEvent 对象StorageEvent 对象的属性属性 类型 描述key 字符串 加入,修改,或者删除的键名oldValue 任意 之前的数据(如果是被覆盖的情况)或者null(如果有新数据项加入)newValue 任意 新数据或者null(如果数据项被删除)url 字符串 调用这个触发数据区变动的函数所在的页面地址storage 事件是无法撤销存储区的改动的。在handle_storage()回调方法中,没有办法停止正在发生的对存储区的改动。安博中程在线 7/34
  8. 8. Web Storage 限制安博中程在线每个域默认拥有5MB或2.5MB存储空间。数据最终是以字符串形式,而不是它原来的数据类型进行存储。(例如存储大型整数或者浮点数时,在存储区,会把每个数字存储为单个字符)存储数据如果超过存储空间的配额,就会跑出QUOTA_EXCEED_ERR异常···8/34
  9. 9. IndexedDB介绍什么是IndexedDB?安博中程在线Indexed Database API, 或者简称IndexedDB,是在浏览器中保存结构化数据的一种数据库。为了替代目前已经被废弃的Web SQL Database API。IndexedDB的思想是创建一套API,方便保存和读取JavaScript对象,同时还支持查询及搜索。IndexedDB设计的操作完全是异步进行的。几乎每一次IndexedDB操作,都需要注册onerror或onsuccess事件处理程序,以确保适当地处理结果。浏览器前缀,IndexedDB在IE10中叫 msIndexedDB, 在Firefox中叫mozIndexedDB, 在Chrome中叫webkitIndexedDB。可以在代码前面加上下面这行代码:····var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;JAVASCRIPT9/34
  10. 10. 打开数据库IndexedDB就是一个数据库,IndexedDB最大的特色是使用对象保存数据,而不是使用表来保存数据。一个IndexedDB数据库,就是一组位于相同命名空间下的对象的集合。使用IndexedDB前首先要打开它,即把要打开的数据库名传给indexDB.open()。安博中程在线如果传入的数据库已经存在,就会发送一个打开它的请求;如果传入的数据库还不存在,就会发送一个创建并打开它的请求;总之,调用indexedDB.open()会返回一个IDBRequest对象,在这个对象上可以添加onerror和onsuccess事件处理程序。···10/34
  11. 11. 打开数据库的相关事件打开数据库的代码示例安博中程在线var request, database;request = indexedDB.open("admin");request.onerror = function(event) {alert("打开数据库错误:" + event.target.errorcode);};request.onsuccess = function(event) {database = event.target.result;}JAVASCRIPTevent.target都指向request对象;如果响应的是onsuccess事件,那么event.target.result中将有一个数据库实例对象(IDBDatabse);如果发生了错误,那么event.target.errorCode中将保存一个错误码,表示问题的性质。···11/34
  12. 12. 数据库版本号默认情况下,IndexedDB数据库是没有版本号的。最好一开始就调用setVersion()方法为数据库指定一个版本号(传入一个表示版本号的字符串)。安博中程在线if (database.version != "1.0") {request = database.setVersion("1.0");request.onerror = function(event) {alert("设置版本号时发生错误:" + event.target.errorCode);};request.onsuccess = function() {alert("数据库初始化完成,数据库名:" + database.name + ", 版本:" + database.version);};} else {alert("数据库已经初始化过了。数据库名称:" + database.name + ",版本号:" + database.version);}JAVASCRIPT12/34
  13. 13. 创建对象存储空间建立完数据库连接以后,就要创建对象存储空间。假设我们要保存用户记录,user对象格式可能类似于:创建对象存储空间时,必须指定一个全局唯一个键,这里我们可以用"username"。下面是为了保存用户记录而创建对象存储空间的示例:keyPath属性,就是空间中要保存的对象的一个属性,这个属性将作为存储空间的键来使用。安博中程在线var user = {username: "007",firstName: "James".lastName: "Bond",password: "foo"};JAVASCRIPTvar store = database.createObjectStore("users", {keyPath: "username"}); JAVASCRIPT13/34
  14. 14. 添加数据安博中程在线获得了对象存储空间的引用之后,就可以使用add()或put()方法向其中添加数据。这两个方法都接收一个参数,即要保存的对象,然后这个对象就会被保存到存储空间中。这两个方法的区别在于,如果空间中已经包含了键值相同的对象:也就是说可以把add()理解成插入新值,put()理解成更新原有的值。比如,我们可以用下面的方法来初始化对象存储空间,把返回的请求对象保存在一个变量中,然后再指定onerror或onsuccess事件处理程序,来验证请求是否成功完成:··add()会返回错误;put()则会重写原有对象;···//users中保存着一批的用户对象var i=0, request, requests[], len = users.length;while(i < len) {request = store.add(users[i++]);request.onerror = function() { // 错误处理};request.onsuccess = function() { // 成功};requests.push(request);}JAVASCRIPT14/34
  15. 15. 使用事务在数据库对象上调用transaction()方法就可以创建事务。任何时候,想要读取或修改数据,都要通过事务来组织所有的操作。下面的代码保证只加载users存储空间中的数据,以便通过事务进行访问:如果要访问多个对象存储空间,可以传入字符串数组:上面的两个事务都是以只读的方式访问数据。要修改访问方式,必须在创建事务时传入第二个参数。安博中程在线var transaction = db.transaction("users"); JAVASCRIPTvar transaction = db.transaction(["users", "anotherStore"]); JAVASCRIPT15/34
  16. 16. 访问模式第二个参数表示访问模式,用IDBTransaction接口定义的如下常量表示:IE10+和Firefox4+实现的叫做IDBTransaction, 但在Chrome中则叫webkitIDBTransaction, 所以使用下面的代码可以统一接口:有了这行代码就可以比较方便地为transaction()指定第二个参数:这个事务就可以读写users存储空间了。安博中程在线READ_ONLY(0)表示只读;READ_WRITE(1)表示读写;VERSION_CHANGE(2)表示改变···var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction; JAVASCRIPTvar transaction = db.transaction("users", IDBTransaction.READ_WRITE); JAVASCRIPT16/34
  17. 17. 访问存储空间拿到事务以后,使用objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间。然后就可以:get()和delete()方法都接收一个对象键作为参数。所有的这5个方法都会返回一个新的请求对象。例如:安博中程在线使用add()和put()方法添加数据;使用get()可以取得值;使用delete()可以删除对象;使用clear()可以删除所有对象;····var request = db.transaction("users").objectStore("users").get("007");request.onerror = function(event) {alert("获取对象失败!");};request.onsuccess = function(event) {var result = event.target.result;alert(result.firestName);};JAVASCRIPT17/34
  18. 18. 事务的事件处理函数一个事务可以完成任何多个请求。事务本身也有事件处理程序:onerror和oncomplete。这两个事件可以提供事务级的状态信息。安博中程在线transaction.onerror = function(event) {// 整个事务都被取消了};transaction.oncomplete = fucntion(event) {// 事务成功完成};JAVASCRIPT18/34
  19. 19. 使用游标查询安博中程在线使用事务可以直接通过已知的键来检索单个对象;在需要检索多个对象的情况下,需要在事务内部创建游标。游标就是指向结果集的一个指针,游标指针首先会指向结果集中的第一项,在接到查找下一项的指令时,才会指向下一项。在对象存储空间上调用openCursor()方法可以创建游标。openCursor()方法返回的也是一个请求对象,也需要为该对象指定onsuccess和onerror事件处理函数···var store = db.transaction("users").objectStore("users"),request = store.openCursor();request.onsuccess = function(event) {// 处理成功};request.onerror = function(event) {// 处理失败};JAVASCRIPT19/34
  20. 20. IDBCursor安博中程在线在前面的onsuccess事件处理程序执行时,可以通过event.target.result取得存储空间中的下一个对象。在结果集中有下一项时,result是一个IDBCursor的实例;如果没有下一项,result为null;IDBCursor实例具有以下几个属性:····key: 对象的键;value:实际的对象;direction:数值,表示游标走动的方向。primaryKey:游标使用的键,有可能是对象键,也有可能是索引键(后面会讨论索引)---默认是IDBCursor.NEXT(0), 表示下一项。IDBCursor.NEXT_TO_DUPLICATE(1), 表示下一个不重复的项;IDBCursor.PREV(2)表示前一项;IDBCursor.PREV_NO_DUPLICATE表示前一个不重复的项。-----20/34
  21. 21. 检索结果信息要检索某一个结果信息,可以像下面这样:因为result.value是一个对象,所以显示前要先转成JSON字符串。安博中程在线request.onsuccess=function(event){varcursor=event.target.result;if(cursor){console.log("Key:"+cursor.key+",Value:"+JSON.stringify(cursor.value));}};JAVASCRIPT21/34
  22. 22. 使用游标更新记录cursor.update()调用update()方法可以使用指定的对象更新当前游标的value:安博中程在线request.onsuccess = function(event) {var cursor = event.target.result, value, updateRequest;if (cursor) {if (cursor.key == "foo") {value = cursor.value; // 取得当前值value.password = "magic"; // 更新密码updateRequest = cursor.udpate(value); // 请求保存更新updateRequest.onsuccess = function() {// 处理成功};updateRequest.onerror = function() {// 处理失败};}}};JAVASCRIPT22/34
  23. 23. 使用游标删除记录cursor.delete()调用delete()方法可以删除相应的记录:注意:如果当前的事务没有修改对象存储空间的权限,update()和delete()会抛出错误。安博中程在线request.onsuccess = function(event) {var cursor = event.target.result, value, deleteRequest;if (cursor) { // 检查一下if (cursor.key == "foo") {deleteRequest = cursor.delete(); // 请求删除当前项deleteRequest.onsuccess = function() {// 处理成功};deleteRequest.onerror = function() {// 处理失败};}}};JAVASCRIPT23/34
  24. 24. 移动游标默认情况下每个游标只发起一次请求;要想发起另一次请求,必须调用下面的一个方法:安博中程在线continue(key): 移动到结果集的下一项。参数key是可选的,不指定这个参数,游标移动到下一项;指定这个参数的话,游标会移动到指定键的位置。advance(count): 向前移动count指定的项数。··24/34
  25. 25. 遍历示例下面的例子遍历了对象存储空间中的所有项:调用continue()会触发另一次请求,进而再次调用onsuccess处理程序。如果没有更多项可以遍历时,event.target.result的值为null。安博中程在线request.onsuccess=function(event){varcursor=event.target.result;if(cursor){ //检查一下console.log("key:"+cursor.key+",Value:"+JSON.stringify(cursor.value));cursor.continue(); //移动到下一项}else{console.log("Done!");}};JAVASCRIPT25/34
  26. 26. 键范围IDBKeyRange安博中程在线通过游标查找数据的方式比较有限,键范围(key range)为使用游标增添了一些灵活性。键范围由IDBKeyRange的实例表示。支持标准IDBKeyRange的浏览器有IE10+和Firefox4+, Chrome中的名字叫webkitIDBKeyRange。考虑到不同浏览器中的差异,也是要声明一个本地的类型:····varIDBKeyRange=window.IDBKeyRange||window.webkitIDBKeyRange; JAVASCRIPT26/34
  27. 27. 键范围only()方法第一种键范围方式是使用only()方法,传入想要取得对象的键:这个范围保证只取得键值为"007"的对象。使用这个范围创建的游标和直接访问存储空间并调用get("007")差不多。安博中程在线varonlyRange=IDBKeyRange.only("007"); JAVASCRIPT27/34
  28. 28. 键范围lowerBound()方法第二种定义键范围的方法是指定结果集的下界。下界表示游标开始的位置。下面代码的键范围可以保证游标从键为"007"的对象开始,然后继续前移,直到最后一个对象:如果想要忽略键为"007"的对象本身,从它的下一个对象开始,可以传入第二个参数true:安博中程在线//从键为“007”的对象开始,然后可以移动到最后varlowerRange=IDBKeyRange.lowerBound("007");JAVASCRIPT//从键为“007”的下一个对象开始,然后可以移动到最后varlowerRange=IDBKeyRange.lowerBound("007",true);JAVASCRIPT28/34
  29. 29. 键范围upperBound()方法第三种定义键范围的方法是指定结果集的上界,也就是指定游标不能超过哪个键。指定上界使用upperRange()方法。如果不想包含键为指定值的对象,同样传入第二个参数true:安博中程在线//从头开始,到取得键为"ace"的对象为止varupperRange=IDBKeyRange.upperBound("ace");JAVASCRIPT//从头开始,到取得键为"ace"的上一个对象为止varupperRange=IDBKeyRange.upperBound("ace",true);JAVASCRIPT29/34
  30. 30. 键范围bound()方法使用bound()方法可以同时指定上下界。这个方法可以接收四个参数:表示下界的键,表示上界的键,可选的表示是否跳过下界的布尔值和可选的表示是否跳过上界的布尔值。安博中程在线varupperRange=IDBKeyRange.bound("007","ace");varupperRange=IDBKeyRange.bound("007","ace",true);varupperRange=IDBKeyRange.bound("007","ace",true,true);varupperRange=IDBKeyRange.bound("007","ace",false,true);JAVASCRIPT30/34
  31. 31. 使用KeyRange的openCursor()方法定义好了key range之后,就可以把它传给openCursor()方法,就能得到一个符合相应约束条件的游标。安博中程在线varstore=db.transaction("users").objectStore("users"),range=IDBKeyRange.bound("007","ace"),request=store.openCursor(range);request.onsuccess=function(event){varcursor=event.target.result;if(cursor){console.log("Key:"+cursor.key+",Value:"+JSON.stringify(cursor.value));cursor.continue();//移动到下一项}else{console.log("Done!");}};JAVASCRIPT31/34
  32. 32. 设定游标方向安博中程在线openCursor()可以接收两个参数,一个是刚才的IDBKeyRange实例,第二个是表示方向的数值常量,也就是前面讲到的IDBCursor中的常量。正常情况下,游标都是从存储空间的第一项开始,调用continue()或advance()前进到最后一项。游标的默认方向值是IDBCursor.NEXT。也可以创建一个游标,从最后一个对象开始,逐个迭代,直到第一个对象,这时要传入的常量是:IDBCursor.PREV。kuailef···varstore=db.transaction("users").objectStore("users"),request=store.openCursor(null,IDBCursor.PREV);//null表示使用默认的值范围,也就是包含所有对象。JAVASCRIPT32/34
  33. 33. 扩展阅读安博中程在线MDC: DOM StorageMDC: IndexedDBBeyond HTML5: Database APIs and the Road to IndexedDB···33/34
  34. 34. <Thank you!>Feel free to contact me if you have any question.微博 @范圣刚博客 www.tfan.orggithub github.com/princetoad

×