60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
import * as store from './itemsStore.js'
|
|
|
|
interface AddTask { type: 'add', id: number }
|
|
interface SelectTask { type: 'select', id: number }
|
|
interface DeselectTask { type: 'deselect', id: number }
|
|
interface ReorderTask { type: 'reorder', id: number, afterId: number | null }
|
|
|
|
type Task = AddTask | SelectTask | DeselectTask | ReorderTask
|
|
|
|
class RequestQueue {
|
|
private addQueue: AddTask[] = []
|
|
private reorderQueue: ReorderTask[] = []
|
|
private pendingKeys = new Set<string>()
|
|
|
|
constructor() {
|
|
setInterval(() => this.flushAdd(), 10_000)
|
|
setInterval(() => this.flushReorder(), 1_000)
|
|
}
|
|
|
|
enqueue(task: Task): boolean {
|
|
if (task.type === 'reorder') {
|
|
this.reorderQueue.push(task)
|
|
return true
|
|
}
|
|
|
|
const key = `${task.type}:${(task as AddTask | SelectTask | DeselectTask).id}`
|
|
if (this.pendingKeys.has(key)) return false
|
|
this.pendingKeys.add(key)
|
|
|
|
if (task.type === 'add') {
|
|
this.addQueue.push(task)
|
|
if (this.addQueue.length >= 100) this.flushAdd()
|
|
}
|
|
else {
|
|
// select/deselect применяются немедленно, чтобы GET после POST видел актуальный state
|
|
if (task.type === 'select') store.selectItem(task.id)
|
|
else if (task.type === 'deselect') store.deselectItem(task.id)
|
|
this.pendingKeys.delete(key)
|
|
}
|
|
return true
|
|
}
|
|
|
|
private flushAdd(): void {
|
|
const batch = this.addQueue.splice(0)
|
|
for (const task of batch) {
|
|
store.addItem(task.id)
|
|
this.pendingKeys.delete(`add:${task.id}`)
|
|
}
|
|
}
|
|
|
|
private flushReorder(): void {
|
|
const batch = this.reorderQueue.splice(0)
|
|
for (const task of batch) {
|
|
store.reorderItem(task.id, task.afterId)
|
|
}
|
|
}
|
|
}
|
|
|
|
export const queue = new RequestQueue()
|