fix(quick-save): Drain-Trailing-Re-Run gegen verworfene onChanged waehrend laufendem Drain (Latenz, kein Verlust)
This commit is contained in:
+25
-21
@@ -233,39 +233,43 @@ function bindGlobalEvents() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- LIVE-SYNC (Quick-Save aus dem Background) ----
|
// ---- QUICK-SAVE PENDING-QUEUE ----
|
||||||
// Ein Quick-Save schreibt boards im Background. Ein offener Tab muss das sehen,
|
// Der Background-Worker haengt Quick-Saves an den eigenen Store-Key 'quicksave_pending' an (er
|
||||||
// sonst ueberschreibt er den Eintrag beim naechsten eigenen Save (QS-03).
|
// schreibt NIE boards). Diese Seite ist die einzige boards-Schreiberin und drained die Queue in die
|
||||||
// Drained die Quick-Save-Queue in die Inbox. Die SEITE ist die einzige Schreiberin von 'boards';
|
// Inbox. Getrennte Schreib-Domaenen -> Worker und Seite koennen sich nicht im boards-Array
|
||||||
// der Background-Worker haengt nur an 'quicksave_pending' an. Dadurch koennen sich Worker und Seite
|
// gegenseitig ueberschreiben (Datensicherheit, Phase-4-Review-Blocker 2b).
|
||||||
// nicht im boards-Array gegenseitig ueberschreiben (Datensicherheit, Phase-4-Review-Blocker 2b).
|
|
||||||
let _drainBusy = false;
|
let _drainBusy = false;
|
||||||
|
let _drainQueued = false; // ein waehrend eines laufenden Drains angefragter Drain wird nachgeholt
|
||||||
async function drainQuickSavePending() {
|
async function drainQuickSavePending() {
|
||||||
if (_drainBusy) return; // Re-Entry-Schutz (init + onChanged koennten ueberlappen)
|
if (_drainBusy) { _drainQueued = true; return; }
|
||||||
_drainBusy = true;
|
_drainBusy = true;
|
||||||
try {
|
try {
|
||||||
const pending = await Store.get('quicksave_pending');
|
const pending = await Store.get('quicksave_pending');
|
||||||
if (!Array.isArray(pending) || pending.length === 0) return;
|
if (Array.isArray(pending) && pending.length > 0) {
|
||||||
const drained = pending.slice();
|
const drained = pending.slice();
|
||||||
const drainedIds = new Set(drained.map(e => e && e.id).filter(Boolean));
|
const drainedIds = new Set(drained.map(e => e && e.id).filter(Boolean));
|
||||||
const inbox = await ensureInboxBoard(); // legt die Inbox an, falls noetig; gibt das Board zurueck
|
const inbox = await ensureInboxBoard(); // legt die Inbox an, falls noetig; gibt das Board zurueck
|
||||||
for (const e of drained) {
|
for (const e of drained) {
|
||||||
if (e && typeof e.url === 'string' && e.url) {
|
if (e && typeof e.url === 'string' && e.url) {
|
||||||
inbox.bookmarks.push(normalizeBookmark({ title: e.title, url: e.url }));
|
inbox.bookmarks.push(normalizeBookmark({ title: e.title, url: e.url }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
await saveBoards();
|
||||||
|
// NUR die verarbeiteten Eintraege entfernen — ein gleichzeitiger Worker-Append bleibt erhalten.
|
||||||
|
const still = await Store.get('quicksave_pending');
|
||||||
|
const remaining = Array.isArray(still) ? still.filter(e => e && !drainedIds.has(e.id)) : [];
|
||||||
|
await Store.set('quicksave_pending', remaining);
|
||||||
|
// Render nur, wenn gerade KEIN Drag laeuft (renderBoards->replaceChildren wuerde ihn abreissen).
|
||||||
|
if (!document.querySelector('.board.dragging, .bm-item.dragging-source')) renderBoards();
|
||||||
}
|
}
|
||||||
await saveBoards();
|
|
||||||
// NUR die verarbeiteten Eintraege entfernen — ein gleichzeitiger Worker-Append bleibt erhalten.
|
|
||||||
const still = await Store.get('quicksave_pending');
|
|
||||||
const remaining = Array.isArray(still) ? still.filter(e => e && !drainedIds.has(e.id)) : [];
|
|
||||||
await Store.set('quicksave_pending', remaining);
|
|
||||||
// Render nur, wenn gerade KEIN Drag laeuft (renderBoards->replaceChildren wuerde ihn abreissen).
|
|
||||||
if (!document.querySelector('.board.dragging, .bm-item.dragging-source')) renderBoards();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Quick-Save-Drain fehlgeschlagen:', e && e.message);
|
console.error('Quick-Save-Drain fehlgeschlagen:', e && e.message);
|
||||||
} finally {
|
} finally {
|
||||||
_drainBusy = false;
|
_drainBusy = false;
|
||||||
}
|
}
|
||||||
|
// Kam waehrend des Drains ein weiterer Quick-Save an (onChanged wurde durch _drainBusy verworfen),
|
||||||
|
// jetzt nachholen. Der Eintrag war sicher in der Queue, nur noch nicht eingelesen.
|
||||||
|
if (_drainQueued) { _drainQueued = false; drainQuickSavePending(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live-Sync (QS-03): ein offener NewTab drained die Queue, sobald der Worker etwas anhaengt.
|
// Live-Sync (QS-03): ein offener NewTab drained die Queue, sobald der Worker etwas anhaengt.
|
||||||
|
|||||||
Reference in New Issue
Block a user