Я видел sync-promise, размещенную на Reddit и got into a discussion with the author. Мы заметили некоторые странные несоответствия в отношениях между транзакциями IndexedDB и обещаниями.Несогласованное взаимодействие между транзакциями IndexedDB и Promises
Индексированные транзакции DB автоматически фиксируются при завершении всех событий onsuccess
. Одно из осложнений состоит в том, что вы не можете делать асинхронные операции в обратном вызове onsuccess
, за исключением выполнения другой операции в той же транзакции. Например, вы не можете запустить запрос AJAX в onsuccess
, а затем повторно использовать ту же транзакцию после запроса AJAX, который возвращает некоторые данные.
Что с этим связано? Насколько я понимаю, обещание разрешения всегда должно быть асинхронным. Это означает, что вы не можете использовать обещания без автоматической фиксации транзакции IndexedDB.
Here is an example of what I'm talking about:
var openRequest = indexedDB.open("library");
openRequest.onupgradeneeded = function() {
// The database did not previously exist, so create object stores and indexes.
var db = openRequest.result;
var store = db.createObjectStore("books", {keyPath: "isbn"});
var titleIndex = store.createIndex("by_title", "title", {unique: true});
var authorIndex = store.createIndex("by_author", "author");
// Populate with initial data.
store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
};
function getByTitle(tx, title) {
return new Promise(function(resolve, reject) {
var store = tx.objectStore("books");
var index = store.index("by_title");
var request = index.get("Bedrock Nights");
request.onsuccess = function() {
var matching = request.result;
if (matching !== undefined) {
// A match was found.
resolve(matching);
} else {
// No match was found.
console.log('no match found');
}
};
});
}
openRequest.onsuccess = function() {
var db = openRequest.result;
var tx = db.transaction("books", "readonly");
getByTitle(tx, "Bedrock Nights").then(function(book) {
console.log('First book', book.isbn, book.title, book.author);
return getByTitle(tx, "Quarry Memories");
}).then(function(book) {
console.log('Second book', book.isbn, book.title, book.author);
// With native promises this gives the error:
// InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
// With bluebird everything is fine
});
};
(Полное раскрытие: демонстрация была создана paldepind, а не я)
Я пробовал его в Chrome и Firefox. В Firefox он не работает из-за транзакции, но он действительно работает в Chrome! Какое поведение верно? И если поведение Firefox правильное, разве буквально невозможно использовать «правильные» реализации обещаний с транзакциями IndexedDB?
Другое осложнение: если я загружаю bluebird перед запуском вышеуказанной демонстрации, он работает как в Chrome, так и в Firefox. Означает ли это, что синяя птица решает обещать синхронно? Я думал, что это не должно было это делать!
Конструктор обещаний всегда называется синхронно (в bluebird и в нативных обещаниях). Bluebird - это просто синяя птица - она не разрешается синхронно (тогда все еще выполняются на следующей итерации цепочки. Это говорит о том, что я не понимаю, что проблема с IndexedDB и A + обещает очень хорошо. Я посмотрю, смогу ли я отследить некоторых умных людей. –