Как я могу сделать очень длинную строку с помощью IndexedDB без сбоев браузера?
Я пишу веб-приложение, которое генерирует потенциально большой текстовый файл, который будет загружен пользователем, и вся обработка выполняется в браузере. Пока я могу читать файл объемом более 1 ГБ в небольших кусках, обрабатывать каждый фрагмент, генерировать большой выходной файл пошагово и хранить растущий результат в IndexedDB. Моя более наивная попытка, которая сохранила все результаты в памяти и затем сериализовала их в файл в самом конце, вызывала сбой всех браузеров.
Мой вопрос в два раза:
-
Могу ли я добавить к записи в IndexedDB (либо строку, либо массив), не прочитав сначала все это в памяти? Прямо сейчас:
task.dbInputWriteQueue.push(output);
var transaction = db.transaction("files", "readwrite");
var objectStore = transaction.objectStore("files");
var request = objectStore.get(file.id);
request.onsuccess = function()
{
request.results += nextPartOfOutput
objectStore.put(request.results);
};
вызывает сбои после того, как результат начинает увеличиваться. Я мог бы просто написать кучу небольших записей в базу данных, но потом мне пришлось бы все их прочитать в памяти позже, чтобы скомпоновать их. См. Часть 2 моего вопроса...
-
Могу ли я сделать URL-адрес объекта данных ссылкой на значение в IndexedDB без загрузки этого значения в память? Для небольших строк я могу сделать:
var url = window.URL.createObjectURL(new Blob([myString]), {type: 'text/plain'});
Но для больших строк это не слишком хорошо. Фактически, он падает до загрузки строки. Похоже, что большие чтения с использованием get()
из IndexedDB заставляют Chrome, по крайней мере, сбой (даже при сбое инструментов разработчика).
Было бы быстрее, если бы я использовал Blobs вместо строк? Это дешевая конверсия?
В принципе, мне нужно с помощью JavaScript написать действительно большой файл на диске, не загружая все это в память в любой момент. Я знаю, что вы можете предоставить createObjectURL
файл, но это не работает в моем случае, так как я создаю новый файл из того, который предоставляет пользователь.
Ответы
Ответ 1
Сохранение Blob будет использовать намного меньше места и ресурсов, так как больше нет необходимости в преобразовании в base64. Вы даже можете хранить объекты "text/plain" как blobs:
var blob = new Blob(['blob object'], {type: 'text/plain'});
var store = db.transaction(['entries'], 'readwrite').objectStore('entries');
// Store the object
var req = store.put(blob, 'blob');
req.onerror = function(e) {
console.log(e);
};
req.onsuccess = function(event) {
console.log('Successfully stored a blob as Blob.');
};
Вы можете увидеть больше информации здесь:
https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/
Chrome поддерживает это только с лета 2014 года: http://updates.html5rocks.com/2014/07/Blob-support-for-IndexedDB-landed-on-Chrome-Dev, поэтому вы не можете использовать его в более ранних версиях Chrome.
Ответ 2
Я только что открыла ошибку Chrome, которую я представил 2 года назад, и создал еще одну ошибку для команда FF, связанная с сбоем браузера при создании большого блоба. Создание больших файлов не должно быть проблемой для браузеров.