自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

編程題:實現(xiàn)一個 LazyMan 方法

開發(fā) 前端
今天我們來看一道 JS 編程題。實現(xiàn)一個 LazyMan 方法。希望能夠幫助到你。

大家好,我是前端西瓜哥。今天我們來看一道 JS 編程題。

問題

實現(xiàn)一個LazyMan,可以按照以下方式調用:

LazyMan("Hank")
輸出:
Hi! This is Hank!
LazyMan("Hank").sleep(10).eat("dinner")
輸出
Hi! This is Hank!
//等待10秒..
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")
輸出
//等待5
Wake up after 5
Hi! This is Hank!
Eat supper

以此類推。

需要實現(xiàn)的功能

我們先分析一下需要的效果。

首先是 Lazy('Hank') ,能夠輸出 Hi! This is Hank。

然后是 .sleep(10),會延遲 10 秒后,執(zhí)行 Wake up after 10。之后的 eat 之類的會跟著延遲執(zhí)行。

.eat('dinner'),是直接輸出 Eat dinner。

最后是一個比較特殊的 .sleepFirst(5),它會被放到最前面提前執(zhí)行,再執(zhí)行其他事情。

思路

這道題不簡單,它考察了多個知識點。

首先是它的使用形式為 鏈式調用,即對象的方法調用完后會返回這個對象,然后就可以繼續(xù)調用這個對象的其他方法,形成一條鏈條一樣的調用寫法。

所以,這個 LazyMan('Hank') 應該返回一個對象,這個對象還必須有 sleep、eat、sleepFirst 這些方法。

所以,我先這樣寫:

function LazyMan(name) {
const solver = {
sleep(second) {
return solver;
},
eat(something) {
return solver;
},
sleepFirst(second) {
return solver;
},
};
return solver;
}

solver 的方法也可以返回 this。這里我沒有返回 this,因為擔心有 this 指向丟失的問題。

還有一種是使用 ES6 的 class 寫法。

function LazyMan(name) {
return new MyLazyMan(name);
}
class MyLazyMan {}

多了一層封裝,但可以更好地維護屬性。否則就像我的寫法那樣,需要用閉包來維護變量。

回到正題。

然后我們再實現(xiàn)依次輸出的效果,因為其中的 sleep,是異步的,而且 sleepFirst 還會前置輸出,所以我們不能每執(zhí)行一個方法,就立即輸出。而是要先緩存一下,等到所有方法都調用完之后,再執(zhí)行。

此外,因為要收集好所有任務才開始執(zhí)行,所以我們要用 setTimeout 構造一個異步的宏任務,確保任務的執(zhí)行在同步代碼后執(zhí)行。

function LazyMan(name) {
setTimeout(() => { // 確保不會過早執(zhí)行
run();
});
function run() {
// 依次執(zhí)行任務
}
}

所以,我們需要一個 隊列 來保存。隊列是一種先進先出的線性表,我們用數(shù)組實現(xiàn),理論上性能更好是用鏈表,但要自己實現(xiàn)很麻煩,通常數(shù)據(jù)量也不大,所以開發(fā)中我們用數(shù)組就完事了。

一個重要的分歧點出現(xiàn)了,這個隊列,保存什么?

一種想法是 queue 存一個對象,里面有 msg 和 t,記錄輸出內容,和延遲執(zhí)行的時間。然后我們自己在對象內部執(zhí)行業(yè)務邏輯。

{
msg: `Wake up after 10`,
t: 10,
}

還有一種想法是,queue 里存的是函數(shù),將它們依次執(zhí)行就好。

實現(xiàn)上類似 中間件 的寫法,本質是設計模式的 責任鏈模式。執(zhí)行完當前函數(shù),我們調用 next 去執(zhí)行下一個函數(shù)。如果你用過 Express 框架,可能就覺得比較熟悉。

run 是一個遞歸函數(shù),不停地執(zhí)行自身,從 queue 里取出第一個 task,執(zhí)行它,然后再執(zhí)行 run 方法,直到 queue 為空。

代碼實現(xiàn)

function LazyMan(name) {
const queue = [
{
msg: `Hi! This is ${name}`,
t: undefined,
},
];
setTimeout(() => { // 確保在同步代碼后執(zhí)行
run();
});
function run() { // 依次執(zhí)行任務
if (queue.length === 0) return;
const { msg, t } = queue.shift();
// 不需要延遲執(zhí)行的任務,我把它們轉為同步執(zhí)行了
// 讓它們都一致用異步執(zhí)行也是可以的
if (t === undefined) {
console.log(msg);
run(); // 執(zhí)行
} else {
setTimeout(() => {
console.log(msg);
run();
}, t * 1000);
}
}
const solver = {
sleep(second) {
queue.push({
msg: `Wake up after ${second}`,
t: second,
});
return solver;
},
eat(something) {
queue.push({
msg: `Eat ${something}`,
t: undefined,
});
return solver;
},
sleepFirst(second) {
// 比較特殊,要放到隊列開頭
queue.unshift({
msg: `Wake up after ${second}`,
t: second,
});
return solver;
},
};
return solver;
}

對于 sleep 這些方法,我只是負責讓它們加入隊列,具體的執(zhí)行我都是在 run 里統(tǒng)一處理的。

我去網上看了下其他人的寫法,發(fā)現(xiàn)比較多的是 Express 的 next 這種風格,那我也寫一個吧。

function LazyMan(name) {
return new MyLazyMan(name);
}
class MyLazyMan {
constructor(name) {
this.queue = [];
this.queue.push(() => {
setTimeout(() => {
console.log(`Hi! This is ${name}`);
})
this.next(); // 千萬不要忘記執(zhí)行 next
})
// 這里依舊是確保在同步代碼后執(zhí)行
setTimeout(() => {
this.next();
})
}
next() {
setTimeout(() => {
if (this.queue.length === 0) return;
const task = this.queue.shift();
task();
})
}
eat(something) {
this.queue.push(() => {
console.log(`Eat ${something}`);
this.next();
});
return this;
}
sleep(second) {
this.queue.push(() => {
setTimeout(() => {
console.log(`Wake up after ${second}`);
this.next();
}, second * 1000);
});
return this;
}
sleepFirst(second) {
this.queue.unshift(() => {
setTimeout(() => {
console.log(`Wake up after ${second}`);
this.next();
}, second * 1000)
});
return this;
}
}

這里的注意點是,在 setTimeout 里不要忘記加上 this.next,否則執(zhí)行的鏈條會在中途斷掉。

寫法很多,除此之外還可以用 Promise,用上 async/await,甚至用上 rxjs,讀者可自行去嘗試。

結尾

這道編程題,考察的東西比較多,包括業(yè)務代碼編寫能力、隊列、中間件思想(責任鏈模式)、異步代碼。

責任編輯:姜華 來源: 今日頭條
相關推薦

2024-05-13 08:40:02

Go事件驅動編程

2012-08-23 14:23:33

函數(shù)式編程

2011-09-16 10:00:56

C++

2020-09-24 11:46:03

Promise

2022-08-02 14:21:20

滑動驗證碼鴻蒙

2022-07-13 15:31:29

手繪板canvas鴻蒙

2009-05-08 09:32:27

JavaWeb編程框架

2021-08-02 08:21:53

Python編程語言開發(fā)

2022-01-04 11:08:02

實現(xiàn)Localcache存儲

2012-04-17 10:38:38

女性編程

2011-07-14 14:36:29

Dbgrid多數(shù)據(jù)庫

2022-07-28 14:20:44

懸浮球鴻蒙

2017-12-12 15:24:32

Web Server單線程實現(xiàn)

2014-04-14 15:54:00

print()Web服務器

2022-10-08 08:15:55

GScriptGo 語言

2020-12-17 12:31:16

javascriptDAOlocalStorag

2022-09-14 08:01:54

語法樹編譯器語法糖

2021-04-22 09:57:37

Random方法游戲

2015-05-25 15:06:28

JavaScript函數(shù)式編程

2023-05-22 09:10:53

CSSloading 效
點贊
收藏

51CTO技術棧公眾號