【发布时间】:2014-11-14 17:26:14
【问题描述】:
总结
我想做的很简单:
- 1a。如果图像不是某种类型的本地存储(例如 IndexedDB),则将图像作为字节数组从服务器读取,放入本地存储(作为字节数组或对文件的引用,我不在乎)
- 1b。如果图像在本地存储中,则从本地存储中读取字节数组。将此字节数组显示为 html 页面中的图像。
不知何故,在 Blob、objectURL、indexedDB 和缓存之间,它都变得过于复杂,并且表现出一些奇怪的行为。如果有办法将 ArrayBuffer 直接粘贴到图像中,而不是先转换为 Blob,然后再转换为 ObjectURL,那么我可能会采用这种方法,因为它更简单,并且消除了有问题的 Blob 和一些不必要的步骤。
如果您想查看流程的代码示例,请查看此jsfiddle。请注意,如下所述,jsfiddle 示例中不会出现该问题(出于某种我无法弄清楚的原因)。
我使用 IndexedDB 而不是依赖浏览器缓存是有原因的,所以让我们尽量避免这种讨论,并且与 IndexedDB 似乎在 Chrome 上行为不端的事实无关。
如果其他人遇到过类似的事情或任何关于如何改善这种情况的建议,我很感兴趣。
详情
Chrome 版本 38.0.2125.104 m。
基本上,流程是通过索引检查blob是否在IndexedDB中(参考jsfiddle):
- 1a。如果不是,则从服务器检索 blob (
xhr.open),将 blob 放入 IndexedDB (objectStore.put) 并显示 blob (imgSrc = createTheObjectUrl(blob))。 - 1b。如果是,则从 IndexedDB (
objectStore.get) 中检索 blob,从 blob 创建 URL,将图像 src 设置为 URL。
问题是它最初可以工作,但不久之后(有时当我刷新页面时,有时当我关闭 Chrome 并返回网页时)我在访问 URL 时收到 404(未找到)斑点。
有几点需要注意:-
- 在我对其他浏览器的有限测试中,我没有看到相同的行为 - 其他浏览器似乎工作正常。
- 当我查看 blob-internals 页面 (chrome://blob-internals) 时,我的磁盘上有一个 blob 路径。当它工作时(图像可见),该文件存在,当它开始失败(404 Not Found)时,该文件不存在(即使 blob-internals 仍然引用它)。
- 当我试图在jsfiddle 中重现此问题时,问题并未发生。这是我的代码的剪切和粘贴。不幸的是,我没有这个网络服务器的公共版本,所以我不能证明它失败了。
鉴于 jsfiddle 似乎总是有效,我能想到的只是我的服务器配置方式有些不同。我查看了返回的标头的差异,我可以看到在 jsfiddle 的情况下,启用了缓存。所以,我开始认为这与缓存有关(这可能是一个完全错误的假设)。就好像 Chrome 正在跟踪 blob 的使用并在它超出范围时将其从文件系统中删除,这导致 IndexedDB 中的条目没有文件(这本身似乎是一个错误)。我不想在服务器上启用缓存或使 blob 的生命周期取决于服务器缓存设置。
解决方法
作为一种解决方法,我执行了以下操作:-
- 1a。如果图像不在 IndexedDB 中,则将其作为 Blob 从服务器中检索。将 Blob 转换为 ArrayBuffer。作为 ArrayBuffer 存储在 IndexedDB 中。
- 1b。如果图像在 IndexedDB 中,则检索,将 ArrayBuffer 转换为 Blob,从 Blob 创建 URL,将图像 src 设置为 URL。
这并不理想,因为这意味着我在第一次显示图像时(在它存储在 IndexedDB 中之前)从 blob 中读取数组缓冲区的开销增加了,然后在从 IndexedDB 中检索。也许有一些聪明的共享资源正在进行,这意味着它们使用相同的底层缓冲区,但这意味着依赖于实现来提高性能。
还有更多 - 如果我从服务器返回的 Blob 创建一个新的 Blob,或者从 Blob 创建一个 ArrayBuffer,然后从 ArrayBuffer 中创建一个新的 Blob,它仍然不起作用。就好像正在使用某种共享引用计数资源。也就是说 - 我能想到的任何涉及在 IndexedDB 中存储 blob 的解决方法都不起作用。
【问题讨论】:
-
Chrome 的一个很好的解决方法,在 iOS 中不起作用,所以我现在正在研究。
-
@ChristopherGrigg,感谢您的评论。我将移植到 iOS,所以我很想知道你发现了什么。
标签: javascript google-chrome indexeddb