Mobile Safari 10 IndexedDB Blob

Mobile Safari 10 IndexedDB Blobs

Safari 10 中的 IndexedDB 现在支持 blob。这在桌面上运行良好,但是 iOS 10 上的移动 Safari 会引发错误:

UnknownError

有时组合使用:

TransactionInactiveError (DOM IDBDatabase Exception): Failed to store record in an IDBObjectStore:
The transaction is inactive or finished.

代码(缩写):

var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB,
    READ_WRITE = IDBTransaction && IDBTransaction.READ_WRITE ? IDBTransaction.READ_WRITE : 'readwrite',
    storeName = 'files',
    db;

init: function() {
    var request = indexedDB.open('mydb');
    request.onerror = ...;
    request.onupgradeneeded = function() {
        db = request.result;
        db.createObjectStore(storeName);
    };
    request.onsuccess = function() {
        db = request.result;
    };
},

save: function(id, data) {
    var put = function(data) {
            var objectStore = db.transaction([storeName], READ_WRITE).objectStore(storeName),
                request = objectStore.put(data, id);

            request.onerror = ...;
            request.onsuccess = ...;
        };

    // not all IndexedDB implementations support storing blobs, only detection is try-catch
    try {
        put(data);
    } catch(err) {
        if (data instanceof Blob) {
            Helpers.blobToDataURL(data, put);
        }
    }
}

在 Mobile Safari 10 上 .put() 不会像以前那样抛出,只会在稍后的异步错误回调中抛出。

Base64 字符串工作正常。

Mobile Safari 中存在错误,还是我必须更改代码?

测试用例:http://fiddle.jshell.net/j7wh60vo/7/

在我看来,这个错误就像您必须更改代码一样。该错误并不表示 blob 存在问题。该错误表明您在调用函数的某个地方有问题。为了更好地回答您的问题,您需要 post 更多的周边代码。具体来说,显示您创建交易和创建交易请求的代码部分。

编辑:首先,删除 window.indexedDB 内容。其次,不要按照你使用它的方式使用 'db',因为那将不起作用,数据库可能会在调用保存时关闭。

function save(id, data) {
  var openRequest = indexedDB.open(...);
  openRequest.onerror = console;
  openRequest.onsuccess = function(event) {
    var db = openRequest.result;
    // Open the transaction
    var tx = db.transaction(storeName, 'readwrite');
    var store = tx.objectStore(storeName);
    // Immediately use the transaction
    try {
      var putRequest = tx.put(data, id);
      putRequest.onerror = console;
    } catch(error) {
      console.log(error);
    }
  };
}

Edit2:附加说明:

前缀已被删除,只使用 indexedDB,而不是 mozIndexedDB 或 webkitIndexedDB 等

事务模式常量已被删除,使用 'readonly' 或 'readwrite',或什么都不用(默认为只读)

我有点不明白你怎么称呼request = transaction.put。据我所知,规范 https://w3c.github.io/IndexedDB/#idbtransaction 中没有方法 IDBTransaction.prototype.put。我很困惑为什么 Mozilla 文档显示带有 transaction.put 的示例。检查 IDBTransaction 的原型 Chrome 55 没有显示 put 方法。

有IDBObjectStore.prototype.put。您的代码根本不应该像当前编写的那样在任何平台上运行。因此,如果它确实有效,我会感到惊讶。你应该只使用像 var store = transaction.objectStore('store'); store.put(obj); 这样你调用对象存储的东西。

运行 跨过同样的问题。 Chrome 54 和 Safari 10 在桌面上运行良好,但在移动 Safari 上,我在尝试将 Blob 存储到 IndexedDB 时不断收到 Unknown 错误。我可以确认这确实只是 Mobile Safari 上 Blob 的问题,而不是 API.

的一些误用

幸运的是,ArrayBuffers 工作正常。所以我下载了如下图片:

xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';

然后以ArrayBuffers的形式保存到IndexedDB中,拉出来后转成Blob得到一个url:

putRequest = objectStore.put(arrayBuffer, id);
putRequest.onsuccess = function(event) {
  objectStore.get(id).onsuccess = function(event) {
    var blob = new Blob([event.target.result], { type: 'image/jpeg'});
    var URL = window.URL || window.webkitURL;
    blobUrl = URL.createObjectURL(blob);
  };
};

我宁愿不必像这样将 ArrayBuffers 转换为 Blob,因为我认为这会降低性能。但它有效。