diff --git a/client/components/Reader/ServerStorage/ServerStorage.vue b/client/components/Reader/ServerStorage/ServerStorage.vue index 7a17af30..0bd9cb8b 100644 --- a/client/components/Reader/ServerStorage/ServerStorage.vue +++ b/client/components/Reader/ServerStorage/ServerStorage.vue @@ -507,10 +507,10 @@ class ServerStorage extends Vue { if (md.key && result[md.key]) result[md.key] = utils.applyObjDiff(result[md.key], md.mod, {isAddChanged: true}); - if (!bookManager.loaded) { + /*if (!bookManager.loaded) { this.warning('Ожидание загрузки списка книг перед синхронизацией'); while (!bookManager.loaded) await utils.sleep(100); - } + }*/ if (newRecent.rev != this.cachedRecent.rev) await this.setCachedRecent(newRecent); diff --git a/client/components/Reader/share/bookManager.js b/client/components/Reader/share/bookManager.js index 17e3a063..abfe8cdc 100644 --- a/client/components/Reader/share/bookManager.js +++ b/client/components/Reader/share/bookManager.js @@ -17,9 +17,12 @@ const bmDataStore = localForage.createInstance({ }); //список недавно открытых книг -const bmRecentStore = localForage.createInstance({ +const bmRecentStoreOld = localForage.createInstance({ name: 'bmRecentStore' }); +const bmRecentStoreNew = localForage.createInstance({ + name: 'bmRecentStoreNew' +}); class BookManager { async init(settings) { @@ -28,15 +31,74 @@ class BookManager { this.eventListeners = []; this.books = {}; - this.recent = {}; - this.recentLast = await bmRecentStore.getItem('recent-last'); - if (this.recentLast) { - this.recent[this.recentLast.key] = this.recentLast; - const meta = await bmMetaStore.getItem(`bmMeta-${this.recentLast.key}`); - if (_.isObject(meta)) { - this.books[meta.key] = meta; + this.recent = {}; + this.saveRecent = _.debounce(() => { + bmRecentStoreNew.setItem('recent', this.recent); + }, 300, {maxWait: 800}); + + this.saveRecentItem = _.debounce(() => { + bmRecentStoreNew.setItem('recent-item', this.recentItem); + this.recentRev++; + bmRecentStoreNew.setItem('rev', this.recentRev); + }, 200, {maxWait: 300}); + + //загрузка bmRecentStore + this.recentRev = await bmRecentStoreNew.getItem('rev') || 0; + if (this.recentRev) { + this.recent = await bmRecentStoreNew.getItem('recent'); + if (!this.recent) + this.recent = {}; + + this.recentItem = await bmRecentStoreNew.getItem('recent-item'); + if (this.recentItem) + this.recent[this.recentItem.key] = this.recentItem; + + this.recentLastKey = await bmRecentStoreNew.getItem('recent-last-key'); + if (this.recentLastKey) { + const meta = await bmMetaStore.getItem(`bmMeta-${this.recentLastKey}`); + if (_.isObject(meta)) { + this.books[meta.key] = meta; + } } + + await this.cleanRecentBooks(); + + } else {//TODO: убрать после 06.2021, когда bmRecentStoreOld устареет + this.recentLast = await bmRecentStoreOld.getItem('recent-last'); + if (this.recentLast) { + this.recent[this.recentLast.key] = this.recentLast; + const meta = await bmMetaStore.getItem(`bmMeta-${this.recentLast.key}`); + if (_.isObject(meta)) { + this.books[meta.key] = meta; + } + } + + let key = null; + const len = await bmRecentStoreOld.length(); + for (let i = len - 1; i >= 0; i--) { + key = await bmRecentStoreOld.key(i); + if (key) { + let r = await bmRecentStoreOld.getItem(key); + if (_.isObject(r) && r.key) { + this.recent[r.key] = r; + } + } else { + await bmRecentStoreOld.removeItem(key); + } + } + + //размножение для дебага + /*if (key) { + for (let i = 0; i < 1000; i++) { + const k = this.keyFromUrl(i.toString()); + this.recent[k] = Object.assign({}, _.cloneDeep(this.recent[key]), {key: k, touchTime: Date.now() - 1000000, url: utils.randomHexString(300)}); + } + }*/ + + await bmRecentStoreNew.setItem('recent', this.recent); + this.recentRev = 1; + await bmRecentStoreNew.setItem('rev', this.recentRev); } this.recentChanged = true; @@ -44,9 +106,7 @@ class BookManager { this.loadStored();//no await } - //Долгая асинхронная загрузка из хранилища. - //Хранение в отдельных записях дает относительно - //нормальное поведение при нескольких вкладках с читалкой в браузере. + //Ленивая асинхронная загрузка bmMetaStore async loadStored() { //даем время для загрузки последней читаемой книги, чтобы не блокировать приложение await utils.sleep(2000); @@ -73,32 +133,7 @@ class BookManager { } } - let key = null; - len = await bmRecentStore.length(); - for (let i = len - 1; i >= 0; i--) { - key = await bmRecentStore.key(i); - if (key) { - let r = await bmRecentStore.getItem(key); - if (_.isObject(r) && r.key) { - this.recent[r.key] = r; - } - } else { - await bmRecentStore.removeItem(key); - } - } - - //размножение для дебага - /*if (key) { - for (let i = 0; i < 1000; i++) { - const k = this.keyFromUrl(i.toString()); - this.recent[k] = Object.assign({}, _.cloneDeep(this.recent[key]), {key: k, touchTime: Date.now() - 1000000, url: utils.randomHexString(300)}); - } - }*/ - await this.cleanBooks(); - await this.cleanRecentBooks(); - - this.recentChanged = true; this.loaded = true; this.emit('load-stored-finish'); } @@ -331,6 +366,43 @@ class BookManager { } //-- recent -------------------------------------------------------------- + async recentSetItem(item = null, skipCheck = false) { + const rev = await bmRecentStoreNew.getItem('rev'); + if (rev != this.recentRev && !skipCheck) { + const newRecent = await bmRecentStoreNew.getItem('recent'); + Object.assign(this.recent, newRecent); + this.recentItem = await bmRecentStoreNew.getItem('recent-item'); + this.recentRev = rev; + } + + const prevKey = (this.recentItem ? this.recentItem.key : ''); + if (item) { + this.recent[item.key] = item; + this.recentItem = item; + } else { + this.recentItem = null; + } + + this.saveRecentItem(); + + if (!item || prevKey != item.key) { + this.saveRecent(); + } + + this.recentChanged = true; + + if (item) { + this.emit('recent-changed', item.key); + } else { + this.emit('recent-changed'); + } + } + + async recentSetLastKey(key) { + this.recentLastKey = key; + await bmRecentStoreNew.setItem('recent-last-key', this.recentLastKey); + } + async setRecentBook(value) { const result = this.metaOnly(value); result.touchTime = Date.now(); @@ -344,38 +416,25 @@ class BookManager { result.bookPosSeen = this.recent[result.key].bookPosSeen; } - this.recent[result.key] = result; - - await bmRecentStore.setItem(result.key, result); - - this.recentLast = result; - await bmRecentStore.setItem('recent-last', this.recentLast); - - this.recentChanged = true; - this.emit('recent-changed', result.key); + await this.recentSetLastKey(result.key); + await this.recentSetItem(result); return result; } async getRecentBook(value) { - let result = this.recent[value.key]; - if (!result) { - result = await bmRecentStore.getItem(value.key); - if (result) - this.recent[value.key] = result; - } - return result; + return this.recent[value.key]; } async delRecentBook(value) { - this.recent[value.key].deleted = 1; - await bmRecentStore.setItem(value.key, this.recent[value.key]); + const item = this.recent[value.key]; + item.deleted = 1; - if (this.recentLast.key == value.key) { - this.recentLast = null; - await bmRecentStore.setItem('recent-last', this.recentLast); + if (this.recentLastKey == value.key) { + await this.recentSetLastKey(null); } + + await this.recentSetItem(item); this.emit('recent-deleted', value.key); - this.emit('recent-changed', value.key); } async cleanRecentBooks() { @@ -383,24 +442,22 @@ class BookManager { let isDel = false; for (let i = 1000; i < sorted.length; i++) { - await bmRecentStore.removeItem(sorted[i].key); delete this.recent[sorted[i].key]; - await bmRecentStore.removeItem(sorted[i].key); isDel = true; } this.sortedRecentCached = null; if (isDel) - this.emit('recent-changed'); + await this.recentSetItem(); return isDel; } mostRecentBook() { - if (this.recentLast) { - return this.recentLast; + if (this.recentLastKey) { + return this.recent[this.recentLastKey]; } - const oldRecentLast = this.recentLast; + const oldKey = this.recentLastKey; let max = 0; let result = null; @@ -411,10 +468,11 @@ class BookManager { result = book; } } - this.recentLast = result; - bmRecentStore.setItem('recent-last', this.recentLast);//no await + + const newRecentLastKey = (result ? result.key : null); + this.recentSetLastKey(newRecentLastKey);//no await - if (this.recentLast !== oldRecentLast) + if (newRecentLastKey !== oldKey) this.emit('recent-changed'); return result; @@ -445,24 +503,12 @@ class BookManager { delete mergedRecent[i]; } - //"ленивое" обновление хранилища - (async() => { - for (const rec of Object.values(mergedRecent)) { - if (rec.key) { - await bmRecentStore.setItem(rec.key, rec); - await utils.sleep(1); - } - } - })(); - this.recent = mergedRecent; - this.recentLast = null; - await bmRecentStore.setItem('recent-last', this.recentLast); + await this.recentSetLastKey(null); + await this.recentSetItem(null, true); - this.recentChanged = true; this.emit('set-recent'); - this.emit('recent-changed'); } addEventListener(listener) {