前几天我们写了关于如何 在 localStorage 中保存图像和文件 的文章,它讲述的是在今天我们拥有的可用资源中务实的做法。然而,localStorage 存在一些性能问题 - 我们将在本博客的后续文章中进行介绍 - 而我们所期望的未来方法是利用 IndexedDB。在这里,我将带您逐步了解如何在 IndexedDB 中存储图像和文件,然后通过 ObjectURL 来展示它们。
总体方法
首先,让我们讨论一下我们将要创建 IndexedDB 数据库、将文件保存到其中,然后将其读出并在页面中展示所要经历的步骤。
- 创建或打开一个数据库。
- 创建一个 objectStore(如果它还不存在)。
- 将图像文件检索为 Blob。
- 启动一个数据库事务。
- 将该 Blob 保存到数据库中。
- 读出该保存的文件,并从中创建一个 ObjectURL,并将其设置为页面中图像元素的 src 属性。
创建代码
让我们分解一下完成此操作所需的所有代码部分。
创建或打开一个数据库。
// IndexedDB window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB, IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction, dbVersion = 1; /* Note: The recommended way to do this is assigning it to window.indexedDB, to avoid potential issues in the global scope when web browsers start removing prefixes in their implementations. You can assign it to a varible, like var indexedDB… but then you have to make sure that the code is contained within a function. */ // Create/open database var request = indexedDB.open("elephantFiles", dbVersion);
request.onsuccess = function (event) {
console.log(“成功创建/访问 IndexedDB 数据库”);
db = request.result;
db.onerror = function (event) {
console.log(“创建/访问 IndexedDB 数据库出错”);
};
// Google Chrome 的临时解决方案,用于创建 objectStore。将在未来被弃用。
if (db.setVersion) {
if (db.version != dbVersion) {
var setVersion = db.setVersion(dbVersion);
setVersion.onsuccess = function () {
createObjectStore(db);
getImageFile();
};
}
else {
getImageFile();
}
}
else {
getImageFile();
}
}
// 供将来使用。目前仅在最新的 Firefox 版本中可用。
request.onupgradeneeded = function (event) {
createObjectStore(event.target.result);
};
使用此方法的目的是,当数据库创建或版本号升高时触发 onupgradeneeded
事件。此方法目前仅在 Firefox 中受支持,但很快就会在其他 Web 浏览器中可用。如果 Web 浏览器不支持此事件,可以使用已弃用的 setVersion
方法并连接到它的 onsuccess
事件。
创建一个 objectStore(如果它还不存在)。
// Create an objectStore console.log("Creating objectStore") dataBase.createObjectStore("elephants");
在这里,您将创建一个 ObjectStore,用于存储您的数据 - 在我们的例子中是文件 - 并且创建后您无需再次创建它,只需更新其内容即可。
将图像文件检索为 Blob。
// Create XHR and BlobBuilder var xhr = new XMLHttpRequest(), blob; xhr.open("GET", "elephant.png", true); // Set the responseType to blob xhr.responseType = "blob"; xhr.addEventListener("load", function () { if (xhr.status === 200) { console.log("Image retrieved"); // File as response blob = xhr.response; // Put the received blob into IndexedDB putElephantInDb(blob); } }, false); // Send XHR xhr.send();
此代码直接将文件的全部内容作为 Blob
获取。目前,此方法仅在 Firefox 中受支持。
收到整个文件后,将 Blob 发送到该函数,以便将其存储到数据库中。
启动一个数据库事务。
// Open a transaction to the database var transaction = db.transaction(["elephants"], IDBTransaction.READ_WRITE);
要开始写入数据库,您需要使用 objectStore 名称和要执行的操作类型启动一个事务 - 在这种情况下是读和写。
将该 Blob 保存到数据库中。
// Put the blob into the dabase transaction.objectStore("elephants").put(blob, "image");
事务启动后,您可以获取所需的 objectStore 的引用,然后将 Blob 放入其中并为其指定一个键。
读出该保存的文件,并从中创建一个 ObjectURL,并将其设置为页面中图像元素的 src 属性。
// Retrieve the file that was just stored transaction.objectStore("elephants").get("image").onsuccess = function (event) { var imgFile = event.target.result; console.log("Got elephant!" + imgFile); // Get window.URL object var URL = window.URL || window.webkitURL; // Create and revoke ObjectURL var imgURL = URL.createObjectURL(imgFile); // Set img src to ObjectURL var imgElephant = document.getElementById("elephant"); imgElephant.setAttribute("src", imgURL); // Revoking ObjectURL URL.revokeObjectURL(imgURL); };
使用相同的交易获取您刚存储的图像文件,然后创建一个 ObjectURL 并将其设置为页面中图像的 src
属性。
同样,也可以将此操作应用于 JavaScript 文件,将其附加到 script
元素,然后对其进行解析。
完整代码
以下是完整的可运行代码。
(function () { // IndexedDB var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB, IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction, dbVersion = 1.0; // Create/open database var request = indexedDB.open("elephantFiles", dbVersion), db, createObjectStore = function (dataBase) { // Create an objectStore console.log("Creating objectStore") dataBase.createObjectStore("elephants"); }, getImageFile = function () { // Create XHR and BlobBuilder var xhr = new XMLHttpRequest(), blob; xhr.open("GET", "elephant.png", true); // Set the responseType to blob xhr.responseType = "blob"; xhr.addEventListener("load", function () { if (xhr.status === 200) { console.log("Image retrieved"); // Blob as response blob = xhr.response; // Put the received blob into IndexedDB putElephantInDb(blob); } }, false); // Send XHR xhr.send(); }, putElephantInDb = function (blob) { console.log("Putting elephants in IndexedDB"); // Open a transaction to the database var transaction = db.transaction(["elephants"], IDBTransaction.READ_WRITE); // Put the blob into the dabase transaction.objectStore("elephants").put(blob, "image"); // Retrieve the file that was just stored transaction.objectStore("elephants").get("image").onsuccess = function (event) { var imgFile = event.target.result; console.log("Got elephant!" + imgFile); // Get window.URL object var URL = window.URL || window.webkitURL; // Create and revoke ObjectURL var imgURL = URL.createObjectURL(imgFile); // Set img src to ObjectURL var imgElephant = document.getElementById("elephant"); imgElephant.setAttribute("src", imgURL); // Revoking ObjectURL URL.revokeObjectURL(imgURL); }; }; request.onerror = function (event) { console.log("Error creating/accessing IndexedDB database"); }; request.onsuccess = function (event) { console.log("Success creating/accessing IndexedDB database"); db = request.result; db.onerror = function (event) { console.log("Error creating/accessing IndexedDB database"); }; // Interim solution for Google Chrome to create an objectStore. Will be deprecated if (db.setVersion) { if (db.version != dbVersion) { var setVersion = db.setVersion(dbVersion); setVersion.onsuccess = function () { createObjectStore(db); getImageFile(); }; } else { getImageFile(); } } else { getImageFile(); } } // For future use. Currently only in latest Firefox versions request.onupgradeneeded = function (event) { createObjectStore(event.target.result); }; })();
Web 浏览器支持
- IndexedDB
- 从很久以前开始就一直受 Firefox 和 Google Chrome 支持(多个版本之前)。计划在 IE10 和 Opera 的未来版本中支持。Safari 的情况尚不清楚。
- onupgradeneeded
- 在最新的 Firefox 中受支持。计划很快在 Google Chrome 中支持,并且有望在 IE10 和 Opera 的未来版本中支持。Safari 的情况尚不清楚。
- 在 IndexedDB 中存储文件
- 在 Firefox 11 及更高版本中受支持。计划在 Google Chrome 中支持。希望 IE10 也能支持它。Safari 和 Opera 的情况尚不清楚。
- XMLHttpRequest Level 2
- Firefox 和 Google Chrome 从很久以前开始就一直支持,Safari 5+ 也支持,计划在 IE10 和 Opera 12 中支持。
- responseType “blob”
- 目前仅在 Firefox 中受支持。很快就会在 Google Chrome 中支持,并计划在 IE10 和 Opera 12 中支持。Safari 的情况尚不清楚。
演示和代码
我整理了一个 使用 IndexedDB 在其中保存图像和文件的演示,您可以亲眼看到它的运行情况。请确保使用任何开发者工具来检查图像的元素,查看其 src
属性的值。还要确保检查 console.log 消息以跟踪操作。
在 IndexedDB 中存储文件的代码 也在 GitHub 上提供,所以赶快去玩吧!
关于 Robert Nyman [荣誉编辑]
Mozilla Hacks 的技术布道师和编辑。就 HTML5、JavaScript 和开放式 Web 发表演讲和撰写博客。Robert 是 HTML5 和开放式 Web 的坚定支持者,自 1999 年以来一直从事 Web 前端开发工作 - 在瑞典和纽约市。他定期在 http://robertnyman.com 上发布博客,并且喜欢旅行和结识新朋友。
30 条评论