實(shí)現(xiàn)一個方法的鏈?zhǔn)秸{(diào)用
題目描述
請使用 TypeScript 實(shí)現(xiàn)一個支持鏈?zhǔn)秸{(diào)用的 Cat 類,要求如下:
cat.say("Tom"):立即輸出hello Tom到控制臺;cat.sleep(3000):等待 3000 毫秒后再繼續(xù)執(zhí)行后續(xù)任務(wù);cat.bye("Bye"):輸出 Bye 到控制臺。
調(diào)用示例:
const cat = new Cat();
cat.say("Tom").sleep(3000).bye("Bye");期望輸出:
hello Tom
# 等待 3 秒...
Bye題目解析
這個需求是一個典型的 異步鏈?zhǔn)秸{(diào)用 場景,尤其是 sleep 延遲后再繼續(xù)執(zhí)行后續(xù)操作。實(shí)現(xiàn)時關(guān)鍵在于:
- 每次調(diào)用都注冊一個異步任務(wù);
- 按順序排隊(duì)執(zhí)行(使用
Promise鏈或任務(wù)隊(duì)列); - 每個方法返回
this以保持鏈?zhǔn)秸{(diào)用。
代碼實(shí)現(xiàn)
class Cat {
private taskQueue: (() => Promise<void>)[] = [];
constructor() {
// 自動開始執(zhí)行任務(wù)隊(duì)列
Promise.resolve().then(() => this.runQueue());
}
private async runQueue() {
for (const task of this.taskQueue) {
await task();
}
}
say(name: string): this {
this.taskQueue.push(() => {
return new Promise<void>((resolve) => {
console.log("hello", name);
resolve();
});
});
return this;
}
sleep(ms: number): this {
this.taskQueue.push(() => {
return new Promise<void>((resolve) => {
setTimeout(resolve, ms);
});
});
return this;
}
bye(msg: string): this {
this.taskQueue.push(() => {
return new Promise<void>((resolve) => {
console.log(msg);
resolve();
});
});
return this;
}
}
// 使用方式
const cat = new Cat();
cat.say("Tom").sleep(3000).bye("Bye");說明:
- taskQueue 是一個異步任務(wù)列表。
- 每個方法通過 this.taskQueue.push(() => Promise) 添加一個任務(wù)。
- 構(gòu)造函數(shù)中立即開始異步執(zhí)行任務(wù)隊(duì)列。
- sleep 實(shí)現(xiàn)延遲,后續(xù)任務(wù)自然排隊(duì)執(zhí)行。
拓展
如果要進(jìn)行逆向鏈?zhǔn)秸{(diào)用,如何實(shí)現(xiàn)呢?
cat.bye("Bye").sleep(2000).say("Say");執(zhí)行順序:
Say
# 等待 2 秒...
Bye所有方法仍然鏈?zhǔn)秸{(diào)用,但執(zhí)行順序以調(diào)用順序?yàn)闇?zhǔn),同時 sleep 是延遲“下一個任務(wù)”的執(zhí)行,而不是“當(dāng)前任務(wù)”的延遲。
class Cat {
private queue: { fn: () => void; delay: number }[] = [];
private nextDelay = 0;
constructor() {
Promise.resolve().then(() => this.run());
}
private async run() {
for (const task of this.queue) {
if (task.delay > 0) {
await new Promise((res) => setTimeout(res, task.delay));
}
task.fn();
}
}
private addTask(fn: () => void): this {
this.queue.push({ fn, delay: this.nextDelay });
this.nextDelay = 0; // reset after applying
return this;
}
say(msg: string): this {
return this.addTask(() => {
console.log(msg);
});
}
bye(msg: string): this {
return this.addTask(() => {
console.log(msg);
});
}
sleep(ms: number): this {
this.nextDelay = ms; // apply to next task
return this;
}
}

























