摘要:前言之前在掘金上到一篇文章關(guān)于微信面試的文章,其中提到了手動實現(xiàn)的問題??雌饋砗孟裢τ腥さ?,我們來分析以下分析首先我們看到例子有幾個特點,一個是我們調(diào)用的時候不需要用到關(guān)鍵字,這意味著我們需要使用工廠函數(shù)另一個是要我們實現(xiàn)鏈式調(diào)用。
前言
之前在掘金上到一篇文章關(guān)于微信面試的文章,其中提到了手動實現(xiàn)Lazyman的問題。剛開始
看到Lazyman我是一臉懵逼的,這是什么鬼,后來查了查了一下,才發(fā)現(xiàn),其實就是手動實現(xiàn)
以下功能:
實現(xiàn)一個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 ? 以此類推。
看起來好像挺有趣的,我們來分析以下
分析首先我們看到例子有幾個特點,一個是我們調(diào)用Lazyman的時候不需要用到new關(guān)鍵字,這意味著我們需要使用工廠函數(shù);另一個是要我們實現(xiàn)鏈式調(diào)用。
我們看到LazyMan(“Hank”).eat(“dinner”).eat(“supper”)這樣的形式,無疑是鏈式調(diào)用了;還有一個難點就是 LazyMan(“Hank”).sleepFirst(5).eat(“supper”)
當存在sleepFirst時,我們還要先等待一段時間,然后再開始報名字,這就說明sleepFirst優(yōu)先級更高,不管何時注冊,都要第一個執(zhí)行,仔細想想
有什么可以實現(xiàn)這個呢?明顯我們需要一個任務(wù)隊列,而且sleepFirst放在最前面,然后等所有任務(wù)都安排好了,才開始執(zhí)行任務(wù)隊列
恩?那說明執(zhí)行任務(wù)不能緊跟在插入任務(wù)全程的后面,那我們見他們分進兩個事件隊列就好了,這就需要借助setTimeout函數(shù)了;
除此之外,一個任務(wù)完成了,我們怎么通知任務(wù)隊列去取下一個任務(wù)呢?這就需要一個尾調(diào)用。
經(jīng)過上面的分析,我們可以開始編碼了:
首先,我們先寫工廠函數(shù)
function Lazyman ( name ) { return new _Lazyman ( name ); }
接著我們開始實現(xiàn)Lazyman:
constructor ( name ) { this.tasks = [];//設(shè)置任務(wù)隊列 let task = (name => () => { console.log ( `Hi! This is ${name} !` ); this.next (); }) ( name ); this.tasks.push ( task ); //通過settimeout的方法,將執(zhí)行函數(shù)放入下一個事件隊列中,從而達到先注冊事件,后執(zhí)行的目的 setTimeout ( () => { this.next (); }, 0 ); } //尾調(diào)用函數(shù),一個任務(wù)執(zhí)行完然后再調(diào)用下一個任務(wù) next () { let task = this.tasks.shift (); task && task (); } eat ( food ) { let task = (food => () => { console.log ( `Eat ${food}` ); this.next (); }) ( food ); this.tasks.push ( task ); return this; } sleep ( time ) { let task = (time => () => { setTimeout ( () => { console.log ( `Wake up after ${time} s!` ); this.next (); }, time * 1000 ) }) ( time ); this.tasks.push ( task ); return this; } sleepFirst ( time ) { let task = (time => () => { setTimeout ( () => { console.log ( `Wake up after ${time} s!` ); this.next (); }, time * 1000 ) }) ( time ); this.tasks.unshift ( task );//sleepFirst函數(shù)需要最先執(zhí)行,所以我們需要在任務(wù)隊列前面放入,然后再執(zhí)行后面的任務(wù) return this; } }
通過上面的步驟,我們就實現(xiàn)了一個簡單的Lazyman了
改進上面明明實現(xiàn)了一個Lazyman了呀,還有什么可以改進的?當然有,如果我們調(diào)用eat的時候,想輸出的是Eaaaaaaaaaat ${food}!!!!,然后輸出好飽啊好飽啊
這意味著每次改變,我們都要去修改eat這個函數(shù),這就耦合度太高了,這時候,我們可以采用發(fā)布訂閱的方式,在調(diào)用eat的時候,我們注冊一個監(jiān)聽函數(shù),然后當任務(wù)
執(zhí)行的時候再發(fā)布這個事件,讓對應(yīng)的監(jiān)聽函數(shù)執(zhí)行,這樣就實現(xiàn)了解耦了
一個小小的Lazyman,竟然有如此多的考點,是在讓人受益匪淺,當然,Lazyman還可以使用promise的方式實現(xiàn),當然實現(xiàn)一個手寫的Promise實在有點難(逃),有機會再用promise
實現(xiàn)一次哈
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88231.html
摘要:只需要返回對象本身就可以了。這里只實現(xiàn)一個示例實現(xiàn)鏈式調(diào)用從隊列頭部插入最后一步封裝還有一個大家可以來試一試。如果有想法的話歡迎提出大家交流一下 ES5實現(xiàn)LazyMan lazyman主要原理是: 需要一個隊列保存將要用到的事件 利用閉包將事件保存至隊列中 創(chuàng)建一個中間件next用來觸發(fā)事件 鏈式調(diào)用 使用lazyman需要實現(xiàn)的場景: LazyMan(Tom); // my n...
摘要:實現(xiàn)一個,可以按照以下方式調(diào)用輸出輸出等待秒輸出輸出等待秒以此類推。這是典型的流程控制,問題的關(guān)鍵是如何實現(xiàn)任務(wù)的順序執(zhí)行。 實現(xiàn)一個LazyMan,可以按照以下方式調(diào)用: LazyMan(Hank)輸出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)輸出 Hi! This is H...
摘要:實現(xiàn)一個,可以按照以下方式調(diào)用輸出輸出等待秒輸出輸出等待秒以此類推。這是典型的流程控制,問題的關(guān)鍵是如何實現(xiàn)任務(wù)的順序執(zhí)行。 實現(xiàn)一個LazyMan,可以按照以下方式調(diào)用: LazyMan(Hank)輸出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)輸出 Hi! This is H...
摘要:實現(xiàn)一個,可以按照以下方式調(diào)用輸出輸出等待秒輸出輸出等待秒以此類推。這是典型的流程控制,問題的關(guān)鍵是如何實現(xiàn)任務(wù)的順序執(zhí)行。 實現(xiàn)一個LazyMan,可以按照以下方式調(diào)用: LazyMan(Hank)輸出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)輸出 Hi! This is H...
閱讀 1371·2021-09-10 10:51
閱讀 2835·2019-08-30 15:54
閱讀 3377·2019-08-29 17:11
閱讀 936·2019-08-29 16:44
閱讀 1399·2019-08-29 13:47
閱讀 1095·2019-08-29 13:47
閱讀 1495·2019-08-29 12:23
閱讀 1052·2019-08-28 18:18