The following interview question came up:

// Supports concurrent scheduler, allowing up to 2 tasks to be processed
const scheduler = new Scheduler(2)
scheduler.addTask(1.'1');   // output '1' after 1s
scheduler.addTask(2.'2');  // output '2' after 2s
scheduler.addTask(1.'3');  // output '3' after 2s
scheduler.addTask(1.'4');  // output '4' after 3s
scheduler.start();
Copy the code

At that time, due to nervousness and lack of experience, I suddenly got stuck and couldn’t make it in time (crying). After I came back, I thought about it for a while and came up with the following ideas:

  1. Start with a maxCount to record the number of concurrent tasks allowed, and a Tasks array to hold all the tasks you set up before you start
  2. We need to encapsulate the added task and make it a promise so that we can get the completed state to operate on
  3. We use the Working array to hold running tasks and tasks to hold unfinished tasks
  4. After the task completes, put the first task in the Tasks queue into Working and run it
  5. Thus, through recursion, a concurrent controller can be completed
// Asynchronous scheduler
class Scheduler {
    maxCount = 0
    tasks = []
    working = []
    constructor(count) {
        this.maxCount = count;
    }
    addTask = (timer, content) = > {
        // Control function
        const target = () = > {
            return new Promise((resolve) = > {
                setTimeout(() = > {
                    console.log(content);
                    resolve();
                }, 1000* timer); })}/ / into the queue
        this.tasks.push(target)
    }
    continueWork = (fn) = > {
        // End of recursion (execution complete)
        if (this.tasks.length > 0) {
            // add the following items to the list
            // Determine the subscript
            let idx = -1;
            for (let i = 0; i < this.working.length; i++) {
                if (fn === this.working[i]) {
                    // Replace it and execute
                    idx = i;
                    break; }}// call and run
            const next = this.tasks.shift();
            next().then(() = > {
                this.continueWork(next)
            })
            this.working[idx] = next;
        }
    }
    start = () = > {
        let len = this.tasks.length;
        if (len >= this.maxCount) {
            // Otherwise, it is queued and executed
            this.working = this.tasks.splice(0.this.maxCount);
            console.log(this.working.length)
            this.working.map(fn= > {
                fn().then(() = > {
                    // Call back when done
                    // The current execution is complete
                    this.continueWork(fn); })})}else {
            // Less than the scheduled range: execute all
            this.tasks.map(fn= > fn())
        }
    }
}
Copy the code

Thanks to SukiYu for the new ideas:

class Scheduler {
            constructor(limit) {
                this.limit = limit
                this.number = 0
                this.queue = []
            }
            addTask(timeout, str) {
                this.queue.push([timeout, str])
            }
            start() {
                if (this.number < this.limit&&this.queue.length) {
                    var [timeout, str] = this.queue.shift()
                    this.number++
                    setTimeout(() = > {
                        console.log(str)
                        this.number--
                        this.start()
                    }, timeout * 1000);
                    this.start()
                }
            }
 }
Copy the code