Topic describes
person.talk('hello').sleep(3000).talk('world')
Copy the code
Implement a class Person that supports the chained call above: print Hello and print world 3 seconds later.
Problem analysis
Each method must return the current instance. First we initialize the code as follows:
class Person {
talk(str: string) {
return this;
}
sleep(milSec: number) {
return this; }}const person = new Person();
person.talk("hello").sleep(3000).talk("world");
Copy the code
Let’s examine the member methods one by one:
talk
: Simple, in factconsole.log
sleep
: Also very simple, onesetTimeout
Perfecting the method implementation results in the following code:
class Person {
talk(str: string) {
console.log(str);
return this;
}
sleep(milSec: number) {
setTimeout(() = > {
console.log("get up");
}, milSec);
return this; }}const person = new Person();
person.talk("hello").sleep(3000).talk("world");
Copy the code
Because of the js event loop, the code will output hello and world immediately, and then get up three seconds later, as shown below:
hello
world
Get up after 3 seconds
get up
Copy the code
This topic is essentially a task scheduling problem. Since it is a task scheduling problem, it must be associated with the task queue, and the idea suddenly becomes clear:
- Instead of executing the concrete logic, the member method puts the concrete logic in a task queue and informs the executor to execute it
- Define the actuator method
run
, continuously obtain tasks from the task queue and execute them - When a new task execution notification is received, if a task is being executed or other tasks are waiting in the queue, the current task is blocked until the previous tasks in the queue are cleared. Otherwise, the task is directly executed
The complete code looks like this:
type Task = () = > Promise<boolean>;
class Person {
tasks: Task[] = [];
isRunning: boolean = false;
talk(str: string) {
const fn: Task = () = > {
return new Promise((resolve) = > {
console.log(str);
resolve(true);
});
};
this.tasks.push(fn);
this.run();
return this;
}
sleep(milSec: number) {
const fn: Task = () = > {
return new Promise((resolve) = > {
setTimeout(() = > {
resolve(true);
}, milSec);
});
};
this.tasks.push(fn);
this.run();
return this;
}
run() {
if (this.isRunning || !this.tasks.length) return;
this.isRunning = true;
// Fetch the first task from the queue and execute it
const task = this.tasks.shift() as Task;
task().then(() = > {
this.isRunning = false;
// Execute the next task
this.run(); }); }}const person = new Person();
person.talk("hello").sleep(3000).talk("world");
Copy the code
So far, the work is done ~