const elItems = document.getElementById('items')
const elSuccess = document.getElementById('success')
const elFailure = document.getElementById('failure')
class QueueUnique {
items = []
success = []
failure = []
processing = false
func
constructor(func) {
this.func = func
}
add(item) {
const allItems = [...this.items, ...this.success, ...this.failure]
const addItem = !allItems.some(itm => itm.id === item.id)
if (!addItem) {
console.log(`QueueUnique not adding item ${item.id} because it has already been queued`)
} else {
this.items = [...this.items, item]
console.log(`QueueUnique adding item ${item.id} to queue position ${this.items.length}`)
this.process()
}
}
process() {
this.update() // this method is not needed and just updates the arrays shown on screen
if (!this.processing && this.items.length) {
this.processing = true
const item = this.items[0]
console.log(`QueueUnique start executing item ${item.id}`)
this.func(item).then(() => {
console.log(`QueueUnique success executing item ${item.id}`)
this.complete(true)
}).catch(err => {
console.log(`QueueUnique failure executing item ${item.id} - ${err.message}`)
this.complete(false)
})
}
}
complete(success) {
const item = this.items[0]
this.items = this.items.filter(itm => itm.id !== item.id)
if (success) {
this.success = [...this.success, item]
} else {
this.failure = [...this.failure, item]
}
this.processing = false
this.process()
}
update() {
elItems.innerHTML = this.items.map(item => item.id)
elSuccess.innerHTML = this.success.map(item => item.id)
elFailure.innerHTML = this.failure.map(item => item.id)
}
}
const speak = (item) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('say', item.sayWhat)
resolve()
}, item.delay)
})
}
const queue = new QueueUnique(speak)
const btn1Click = () => {
queue.add({id: 1, sayWhat: 'one', delay: 1000})
}
const btn2Click = () => {
queue.add({id: 2, sayWhat: 'two', delay: 2000})
}
const btn3Click = () => {
queue.add({id: 3, sayWhat: 'three', delay: 3000})
}
const btn4Click = () => {
queue.add({id: 4, sayWhat: 'four', delay: 4000})
}
const btn5Click = () => {
queue.add({id: 5, sayWhat: 'five', delay: 5000})
}
div {
display: inline-block;
margin: 5px 0 0 10px;
padding: 2px 5px;
border-radius: 3px;
background-color: #DDD;
}
<button onclick="btn1Click()">button 1</button>
<button onclick="btn2Click()">button 2</button>
<button onclick="btn3Click()">button 3</button>
<button onclick="btn4Click()">button 4</button>
<button onclick="btn5Click()">button 5</button>
<div>items <span id="items"></span></div>
<div>success <span id="success"></span></div>
<div>failure <span id="failure"></span></div>