Recently in the interview encountered such a pen test, feel very interesting, take out to share. Look at the title:

Implement a LazyMan and get the relevant output when called as follows:

LazyMan("Hank")
// Hi! This is Hank!LazyMan ("Hank").sleep(10).eat("dinner")
// Hi! This is Hank!
// * Wait 10 seconds..
// Wake up after 10
// Eat dinner~LazyMan ("Hank").eat("dinner").eat("supper")
// Hi This is Hank!
// Eat dinner~
// Eat supper~LazyMan ("Hank").sleepFirst(5).eat("supper")
// * Wait 5 seconds
// Wake up after 5
// Hi This is Hank!
// Eat supper
Copy the code

When I first got the topic, I was still confused and didn’t know what to do. However, I settled down to analyze the topic quickly in order to offer.

  1. All calls are chaining based on LazyMan, which allows LazyMan to be constructed as a constructor that returns an instance with some methods;
  2. Instance methods all have the characteristics of chain calls;
  3. The eat method is relatively simple and can output parameters directly
  4. The sleep method pauses the chain call and waits for the appropriate time to resume. Consider using setTimeout;
  5. The sleepFirst method is a special one, similar to sleep, but with the highest priority. No matter where you call it, you start the entire chain call process from scratch.
  6. Given the specific nature of the Sleep and sleepFirst methods, I decided to use task queues to handle “pause” operations.

Next I try to follow the above ideas to use the code to achieve.

class LazyManGenerator {
    constructor(name) {
        this.taskArray = []
        const task = () = > {
            console.log(`Hi! This is ${name}`)
            this.next()
        }

        this.taskArray.push(task);
		// To prevent immediate execution, wait for the array to complete before executing tasks in the task queue.
        setTimeout(() = > { this.next(); }, 0)}next() {
        // Execute the task from scratch
        const task = this.taskArray.shift()
        task && task()
    }

    sleep(time) {
        this.sleepTask(time, false)
            // Support chain calls
        return this
    }

    sleepFirst(time) {
        this.sleepTask(time, true)
        return this
    }

    sleepTask(time, prior) {
        const task = () = > {
            setTimeout(() = > {
                console.log(`Wake up after ${time}`)
                this.next()
            }, time * 1000)}// If the task is sleepFirst, add it from the head, otherwise add it from the tail
        if (prior) {
            this.taskArray.unshift(task);
        } else {
            this.taskArray.push(task);
        }

        return this;
    }

    eat(name) {
        const task = () = > {
            console.log(`Eat ${name}`)
            this.next()
        }

        this.taskArray.push(task)
        return this}}function LazyMan(name) {
    // Returns an instance of the LazyManGenerator constructor
    return new LazyManGenerator(name)
}
Copy the code

The code is not that difficult, just the implementation of the above analysis. The idea is that methods are not executed immediately, but are added to the taskArray array in a specific order, and then executed in sequence after the chain call completes (the tasks are all added to the taskArray array).

The realization is already passing, but the interviewer still continued to ask if there is a better implementation, maybe because of next, LET me think of the implementation of KOA’s middleware, briefly said the idea, in fact, is a simple middleware process control. Capable children can try to achieve the following on their own.