成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

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

問(wèn)題

實(shí)現(xiàn)一個(gè)LazyMan,可以按照以下方式調(diào)用:

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

以此類推。

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

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

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

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

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

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

思路

這道題不簡(jiǎn)單,它考察了多個(gè)知識(shí)點(diǎn)。

首先是它的使用形式為 鏈?zhǔn)秸{(diào)用,即對(duì)象的方法調(diào)用完后會(huì)返回這個(gè)對(duì)象,然后就可以繼續(xù)調(diào)用這個(gè)對(duì)象的其他方法,形成一條鏈條一樣的調(diào)用寫法。

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

所以,我先這樣寫:

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

solver 的方法也可以返回 this。這里我沒(méi)有返回 this,因?yàn)閾?dān)心有 this 指向丟失的問(wèn)題。

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

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

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

回到正題。

然后我們?cè)賹?shí)現(xiàn)依次輸出的效果,因?yàn)槠渲械?sleep,是異步的,而且 sleepFirst 還會(huì)前置輸出,所以我們不能每執(zhí)行一個(gè)方法,就立即輸出。而是要先緩存一下,等到所有方法都調(diào)用完之后,再執(zhí)行。

此外,因?yàn)橐占盟腥蝿?wù)才開(kāi)始執(zhí)行,所以我們要用 setTimeout 構(gòu)造一個(gè)異步的宏任務(wù),確保任務(wù)的執(zhí)行在同步代碼后執(zhí)行。

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

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

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

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

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

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

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

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

代碼實(shí)現(xiàn)

function LazyMan(name) {
const queue = [
{
msg: `Hi! This is ${name}`,
t: undefined,
},
];
setTimeout(() => { // 確保在同步代碼后執(zhí)行
run();
});
function run() { // 依次執(zhí)行任務(wù)
if (queue.length === 0) return;
const { msg, t } = queue.shift();
// 不需要延遲執(zhí)行的任務(wù),我把它們轉(zhuǎn)為同步執(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) {
// 比較特殊,要放到隊(duì)列開(kāi)頭
queue.unshift({
msg: `Wake up after ${second}`,
t: second,
});
return solver;
},
};
return solver;
}

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

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

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(); // 千萬(wàn)不要忘記執(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;
}
}

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

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

結(jié)尾

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

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2025-05-20 08:00:00

鏈?zhǔn)?/a>調(diào)用異步

2024-05-13 08:40:02

Go事件驅(qū)動(dòng)編程

2012-08-23 14:23:33

函數(shù)式編程

2011-09-16 10:00:56

C++

2020-09-24 11:46:03

Promise

2022-07-13 15:31:29

手繪板canvas鴻蒙

2022-08-02 14:21:20

滑動(dòng)驗(yàn)證碼鴻蒙

2009-05-08 09:32:27

JavaWeb編程框架

2021-08-02 08:21:53

Python編程語(yǔ)言開(kāi)發(fā)

2012-04-17 10:38:38

女性編程

2022-01-04 11:08:02

實(shí)現(xiàn)Localcache存儲(chǔ)

2022-07-28 14:20:44

懸浮球鴻蒙

2017-12-12 15:24:32

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

2014-04-14 15:54:00

print()Web服務(wù)器

2011-07-14 14:36:29

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

2022-10-08 08:15:55

GScriptGo 語(yǔ)言

2020-12-17 12:31:16

javascriptDAOlocalStorag

2022-09-14 08:01:54

語(yǔ)法樹(shù)編譯器語(yǔ)法糖

2015-05-25 15:06:28

JavaScript函數(shù)式編程

2011-03-28 09:56:03

存儲(chǔ)增刪操作
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩一区二区视频 | 91传媒在线观看 | 久久一区二区精品 | av大全在线| 成人精品免费视频 | 伊人啪啪网 | 福利视频一区二区三区 | 国产精彩视频在线观看 | 日韩精彩视频 | 日韩看片 | 九九亚洲 | 国产在线小视频 | 欧美在线看片 | 日本一区二区高清视频 | 欧美一二三| 精品久久久久久一区二区 | 国产中文字幕在线观看 | 毛片网络 | 999免费观看视频 | 婷婷激情在线 | 欧美11一13sex性hd | 三级黄色片在线播放 | 91久久精品国产91久久性色tv | 欧美性大战xxxxx久久久 | 紧缚调教一区二区三区视频 | 成人国产一区二区三区精品麻豆 | 九九伊人sl水蜜桃色推荐 | 国产女人与拘做视频免费 | 超碰伊人 | 色综合久久久 | 精品欧美一区二区三区久久久 | 黄色片在线 | 一级在线观看 | 免费在线观看一区二区三区 | 久久精品色欧美aⅴ一区二区 | 欧美日韩国产高清 | 精品久久久久久久久久久久久久 | 国产精品亚洲精品日韩已方 | 国产一区黄色 | 看a网站| 日韩精品色网 |