I met an interview question last year:
Design an asynchronous task scheduler that can have at most two asynchronous tasks running at the same time. The completed asynchronous tasks are queued, and the asynchronous tasks to be queued are queued in the sequence in which they are added.
class Scheduler {
constructor() {... } add(promiseCreator) {... }}/ / use cases:
const timeout = time= >
new Promise(resolve= > {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) = > {
scheduler.add((a)= > timeout(time)).then((a)= > console.log(time, order))
}
addTask(1000.'1')
addTask(500.'2')
addTask(300.'3')
addTask(400.'4')
/ / output:
/ / 500 '2'
/ / 300 '3'
/ / 1000 '1'
/ / 400 '4'
Copy the code
I wrote an async await version of this:
Async await version:
class Scheduler {
constructor() {
this.waitQueue = []
this.count = 0
}
async add(promiseCreator) {
this.count >= 2 && await new Promise(resolve= > this.waitQueue.push(resolve))
this.count++
const res = await promiseCreator()
this.count--
this.waitQueue.length && this.waitQueue.shift()()
return res
}
}
const timeout = time= >
new Promise(resolve= > {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) = > {
scheduler.add((a)= > timeout(time)).then((a)= > console.log(time, order))
}
addTask(1000.'1')
addTask(500.'2')
addTask(300.'3')
addTask(400.'4')
// Execution result:
/ / 500 '2'
/ / 300 '3'
/ / 1000 '1'
/ / 400 '4'
Copy the code
Execution process:
Async is a generator with its own executor, i.e. the former is the syntactic sugar of the latter, and the core is the same. They allow a function to execute in segments, yielding execution when the function encounters await and yield. So the execution flow of the above program is as follows:
- Synchronization task:
addTask(1000, '1')
Perform toconst res = await promiseCreator()
Hand over the executive power and carry out the next stepaddTask(500, '2')
With 1addTask(300, '3')
At this timecount = 2
So the implementation toawait new Promise(resolve => this.waitQueue.push(resolve))
“To hand over executive power and take the next stepaddTask(400, '4')
With 3
- Asynchronous tasks:
time=500
Timer Resolve,addTask(500, '2')
The function regains execution and starts executing the following code:
this.count-- //count = 1
this.waitQueue.length && this.waitQueue.shift()() // Restore execution of the first asynchronous task in waitQueue, resolve, addTask(300, '3'
return res Then (() => console.log(time, order))
Copy the code
addTask(300, '3')
Function regains execution authority and executes toconst res = await promiseCreator()
Surrender of executiontime=300
Resolve timer, the follow-up process is the same as 5addTask(400, '4')
The function regains execution, as in 6time=1000
Resolve timer, the follow-up process is the same as 5time=400
Resolve timer, the follow-up process is the same as 5
Promise version:
Later when I reviewed the Promise, I tried to write a version with the Promise
class Scheduler {
constructor() {
this.promiseCreatorQueue = []
this.waitQueue = []
this.count = 0
}
add(promiseCreator) {
if (this.count >= 2) return new Promise(resolve= > {
this.waitQueue.push(resolve)
this.promiseCreatorQueue.push(promiseCreator)
}).then((a)= > {
this.count++
return this.promiseCreatorQueue.shift()().then((a)= > {
this.count--
this.waitQueue.length && this.waitQueue.shift()()
})
})
this.count++
return promiseCreator().then((a)= > {
this.count--
this.waitQueue.length && this.waitQueue.shift()()
})
}
}
const timeout = time= >
new Promise(resolve= > {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) = > {
scheduler.add((a)= > timeout(time)).then((a)= > console.log(time, order))
}
addTask(1000.'1')
addTask(500.'2')
addTask(300.'3')
addTask(400.'4')
// Execution result:
/ / 500 '2'
/ / 300 '3'
/ / 1000 '1'
/ / 400 '4'
Copy the code
Execute the process
PromiseCreator () returns a Promise Promise that will start the next promiseCreator to start a new asynchronous task
conclusion
As seen from the code, async await greatly simplifies the code and logic.