为离线Web应用程序存储图像数据(客户端存储数据库)

112
我有一个使用应用程序缓存的离线Web应用程序。 我需要提供约10MB-20MB的数据以保存(客户端),主要由PNG图像文件组成。 操作如下:
  1. Web应用程序下载并安装在应用程序缓存中(使用清单)
  2. Web应用程序从服务器请求PNG数据文件(如何?-见下面的替代方案)
  3. 偶尔Web应用程序与服务器进行重新同步,并对PNG数据库进行小的部分更新/删除/添加
  4. FYI:服务器是JSON REST服务器,可以将文件放置在wwwroot以便取用
这是我对处理二进制blob存储的基于客户端的“数据库”的当前分析。

请参见下方更新

  • AppCache(通过清单添加所有PNG文件,然后按需更新)

    • CON:PNG数据库项的任何更改都意味着完全下载清单中的所有项目(非常糟糕!)
  • WebStorage

  • PhoneGap和SQLLite

    • CON:赞助商将拒绝它作为需要认证的本机应用程序
  • ZIP文件

    • 服务器创建zip文件,将其放置在wwwroot中,并通知客户端
    • 用户必须手动解压缩(至少我是这样看的),并保存到客户端文件系统
    • Web应用程序使用FileSystem API引用文件
    • CON:ZIP可能太大(zip64?),创建时间长
    • CON:不确定FileSystem API是否总是可以从沙箱中读取(我认为是)
  • USB或SD卡(回到石器时代...)

    • 用户将在离线前位于服务器位置
    • 因此,我们可以让他插入SD卡,让服务器填充PNG文件
    • 然后用户将其插入笔记本电脑、平板电脑
    • Web应用程序将使用FileSystem API读取文件
    • CON:不确定FileSystem API是否总是可以从沙箱中读取(我认为是)
  • WebSQL

    • CON: W3C已经放弃了它(相当不好)
    • 我可能会考虑一个JavaScript包装器,它使用IndexedDB和WebSQL作为备用方案
  • FileSystem API

  • IndexedDB

  • LawnChair JavaScript包装器:http://brian.io/lawnchair/

    • 优点:非常干净的 IndexedDB、WebSQL 或任何数据库的封装(类似 polyfill)。
    • 缺点:无法存储二进制 blob,只能存储数据:URI(base64 编码),可能由于解码成本而导致致命缺陷。
    • IndexedDB JQUERY polyFill https://github.com/axemclion/jquery-indexeddb

      • Parashuram 写了一个很好的 JQUERY 包装器,用于原始 IndexedDB 接口。
      • 优点:大大简化了使用 IndexedDB,我希望为 Chrome FileSystemAPI 添加一个 shim/polyfill。
      • 缺点:它应该处理 blob,但我无法让它工作。
    • idb.filesystem.js http://ericbidelman.tumblr.com/post/21649963613/idb-filesystem-js-bringing-the-html5-filesystem-api

      • Google 的 Eric Bidelman 编写了一个经过充分测试的 PolyFill FileSystem API,它使用 Indexed DB 作为后备。
      • 优点:FileSystem API 很适合存储 blob。
      • 优点:在 FireFox 和 Chrome 上运行得很好。
        • 优点:非常适合与基于云的 CouchDB 同步。
      • 缺点:不清楚为什么,但它在 IE10 上不能正常工作。
    • PouchDB JavaScript Library http://pouchdb.com/

      • 用于将 CouchDB 与本地数据库同步(使用 WebSQL 或 IndexedDB,不是我的问题)。
      • 缺点:没有缺点,PouchDB 现在支持所有近期浏览器(IE、Chrome、Firefox、移动版 Chrome 等)以及许多旧浏览器的二进制 blob。当我第一次写这篇文章时,情况并非如此。

    注意:要查看我创建的 PNG 的 data:uri 编码示例,请转到:http://jsbin.com/ivefak/1/edit

    期望的/有用的/不需要的功能

    • 客户端没有本地应用程序(如EXE,PhoneGap,ObjectiveC等),仅为纯Web应用程序
    • 只需要在最新的Chrome,FireFox和IE10上运行笔记本电脑
    • 强烈希望Android平板电脑使用相同的解决方案(IOS也可以),但只需要一个浏览器即可工作(FF,Chrome等)
    • 快速进行初始数据库填充
    • 要求:Web应用程序从存储(数据库,文件)中非常快速地检索图像
    • 不适合消费者。我们可以限制浏览器,并要求用户执行特殊设置和任务,但让我们尽量减少这些操作

    IndexedDB实现

    • 有一篇关于IE,Firefox和Chrome如何内部实现此功能的优秀文章:http://www.aaron-powell.com/web/indexeddb-storage
    • 简而言之:
      • IE使用与Exchange和Active Directory相同的数据库格式来实现IndexedDB
      • Firefox正在使用SQLite,因此将NoSQL数据库实现到SQL数据库中
      • Chrome(和WebKit)正在使用源于BigTable的键/值存储

    我的当前结果

    • 我选择使用IndexedDB方法(并使用FileSystemAPI在Chrome上进行polyfill,直到它们支持blob支持)
    • 对于获取瓷砖,我遇到了一个困境,因为JQUERY的人们正在抱怨将其添加到AJAX中
    • 我选择了Phil Parsons的XHR2-Lib,它非常类似于JQUERY .ajax() https://github.com/p-m-p/xhr2-lib
    • 100MB下载的性能(IE10 4s,Chrome 6s,FireFox 7s)。
    • 我无法让任何IndexedDB包装器对blobs起作用(lawnchair,PouchDB,jquery-indexeddb等)
    • 我自己编写了包装器,性能为(IE10 2s,Chrome 3s,FireFox 10s)
    • 对于FF,我假设我们正在看到使用关系数据库(sqllite)存储非关系型数据时出现的性能问题
    • 请注意,Chrome具有出色的调试工具(开发人员选项卡,资源),可用于检查IndexedDB的状态。

    最终结果如下所示:

    更新

    PouchDB现在支持二进制blob以适用于所有最新的浏览器(IE,Chrome,Firefox,移动版Chrome等)以及许多旧版本的浏览器。当我第一次发布此帖子时,情况并非如此。


1
webstorage不支持json,但支持字符串,因此您可以将图像进行base64编码,并将其作为数据URL返回。 - mpm
我更新了这篇文章,加入了我关于 Lawnchair、IDB polyfill 和 Pouch 所发现的新信息,以及 Chrome 团队将要在 Chrome 中添加 Blob 支持的事实。我现在正在进行 FileSystemAPI 与 IDB 的性能测试比较。 - Dr.YSG
似乎Lawnchair确实在Firefox中支持Blob。由于尚未实现(有关此问题的问题https://code.google.com/p/chromium/issues/detail?id=108012),因此它在Chrome中无法正常工作。 - Peppelorum
你确定这些不仅仅是Base64吗?我在Github上还有一个关于blob支持的未解决问题:https://github.com/brianleroux/lawnchair/issues/141 - Dr.YSG
现在我正在使用PouchDB,它有一个适用于Chrome的shim。 - Dr.YSG
显示剩余5条评论
4个回答

27

在PNG地图上离线使用Blob缓存

测试

  • 171个PNG文件(总共3.2MB)
  • 已测试的平台:Chrome v24,FireFox 18,IE 10
  • 也应该适用于Android的Chrome和Firefox

从Web服务器获取

  • 使用XHR2(几乎所有浏览器都支持)从web服务器下载blob
  • 我选择了Phil Parsons的XHR2-Lib,它非常像JQUERY .ajax()

存储

展示

结果

  • Chrome: 获取数据(6.551秒),存储数据(8.247秒),总用时(13.714秒)
  • FireFox: 获取数据(0.422秒),存储数据(31.519秒),总用时(32.836秒)
  • IE 10: 获取数据(0.668秒),存储数据(0.896秒),总用时(3.758秒)

5
对于您的要求,我建议基于两个已有的polyfill,即《FileSystem API to IndexedDB》和《IndexedDB to WebSQL》开发新的polyfill,这是最佳选择。
前者将支持在Chrome(FileSystem API)和Firefox(IndexedDB)中存储二进制大对象,而后者应该为Android和iOS(WebSQL)提供支持。所需的只是使这些polyfills共同工作,我认为这不难。
请注意:由于我在网络上找不到关于此事的任何信息,您应该测试使用WebSQL polyfill存储二进制大对象是否适用于iOS和Android。虽然看起来应该适用。
var sql = ["CREATE TABLE", idbModules.util.quote(storeName), "(key BLOB", createOptions.autoIncrement ? ", inc INTEGER PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY", ", value BLOB)"].join(" ")

来源


我倾向于你的建议,但我正在等待其他人的意见。我没有方便的安卓设备,但创建一个jsBin或jsFiddle并查看在安卓上的效果会很好。 - Dr.YSG
1
这两个 Blob 是不同的。Sqlite 的 Blob 在 JavaScript 中是 ArrayBuffer,而 JavaScript 的 Blob 在 Sqlite 中没有等价物。Blob 不能转换为 ArrayBuffer,尽管它可以进行结构克隆。 - Kyaw Tun

2
我有地图缓存 示例(打开示例,发现区域和缩放,切换离线和已发现的区域将可用)。
其中包括 map.js - 离线瓷砖地图层,storage.js - 基于 IndexedDb 和 WebSQL 的存储实现(但这只是测试实现,性能较差)。
  • 对于网站文件(html、css、js等),我更喜欢使用应用程序缓存。
  • 对于存储,我更喜欢使用Indexed DB(支持blob)、Web SQL(仅支持base64)、FileWriter(支持blob,但仅限Chrome)。坦率地说,存储是一个大问题。您需要最快的键值解决方案,将它们混合在一起。我认为使用现有的解决方案是一个不错的决定。
  • 对于获取数据,我使用带有CORS的canvas。但是我正在考虑使用WebWorkers和XHR2,这可能比canvas更好,因为canvas在不同浏览器和其他情况下存在一些CORS问题(例如this title在Opera中存储bad in opera)。

关于拥有20亿人口的城市明斯克(Minsk)的大小的附加信息:

缩放 - 9,瓷砖 - 2,大小 - 52 kb,带有先前 - 52 kb; 缩放 - 10,瓷砖 - 3,大小 - 72 kb,带有先前 - 124 kb; 缩放 - 11,瓷砖 - 7,大小 - 204 kb,带有先前 - 328 kb; 缩放 - 12,瓷砖 - 17,大小 - 348 kb,带有先前 - 676 kb; 缩放 - 13,瓷砖 - 48,大小 - 820 kb,带有先前 - 1.5 mb; 缩放 - 14,瓷砖 - 158,大小 - 2.2 mb,带有先前 - 3.7 mb; 缩放 - 15,瓷砖 - 586,大小 - 5.5 mb,带有先前 - 9.3 mb; 缩放 - 16,瓷砖 - 2264,大小 - 15 mb,带有先前 - 24.3 mb;

我猜这些是以slippy EGPS3857格式的JPG瓦片,对吧?因为我正在使用leaflet并进行光栅叠加,所以我不得不选择PNG。还请查看我使用PouchDB(它在底层使用IDB)的演示。https://dev59.com/H3LYa4cB1Zd3GeqPYHqt - Dr.YSG
哦,是的,你正在动态缓存,但是你知道我可以去哪里获取预构建的OSM地图(全球范围),下至缩放级别10、11或12吗?我们将在离线服务器上保留此地图。 - Dr.YSG
不,使用默认投影(EGPS:3857)的PNG格式,但无论是JPEG还是PNG都可以,因为它们被img标签或canvas使用。通过我的示例,如果您知道瓦片密钥(对于每个存储的瓦片,使用storage.add('x_y_z', 'data:image/png;base64,...')),则可以预加载瓦片,但是如果只知道边界(多边形)和缩放级别,则始终可以获取它们。 - tbicr
我想确保我们没有语言问题。你知道哪里可以获取全球范围的OSM滑动瓦片集(PNG或JPG),缩放级别为10吗? - Dr.YSG
你可以从 tile.osm.org(mapnik渲染器)获取瓦片。例如,http://tile.openstreetmap.org/10/590/329.png (zoom/x/y.png)。这些瓦片有 Access-Control-Allow-Origin: * 头,因此您可以通过ajax获取它们或通过canvas获取数据uri(base64)。您已经可以使用您的 manifest.json {id: 0-0-0} 下载瓦片,但必须确保具有正确的 zoomxy 序列。 - tbicr
你们为离线地图所做的努力非常出色。现在我们正在考虑并尝试使用你们和类似的技术来进行离线路由。请参见此处:https://dev59.com/y3_aa4cB1Zd3GeqPyhVq - Karussell

1
几年前(不是石器时代),我使用了一个已签名的Java小程序,它会查询其服务器以获取同步/更新要求,从服务器下载适当的文件并将它们保存在用户的文件系统中(而不是数据库)。这种解决方案可能适用于您,尽管您需要有人编写并签署该小程序。对于数据库解决方案,这样的小程序可以使用大多数数据库可用的jdbc,在适当的端口上使用localhost(例如,MySQL的3306端口)。我相信applet标签在Html5中已被弃用,但它仍然有效。对于Android平板电脑没有经验,因此无法对此部分发表评论。

2
我在1968年开始使用卡片打孔机编写FORTRAN程序,因此古老的解决方案对我来说并不陌生。 - Dr.YSG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接