筆者昨天在作某公司的線上筆試題的時候遇到了最後一道關於如何實現LazyMan的試題,題目以下異步
實現一個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~thisLazyMan(「Hank」).sleepFirst(5).eat(「supper」)輸出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此類推。code
鑑於時間的緣由只惋惜本人當時並沒寫出來,我當時腦海裏其實看到提意就知道要用到隊列、Promise等異步操做。而後我查閱了網上的資料好像關於這個LazyMan的實現方式倒很多,就說明這道題其實蠻有意思的,但大多都是關於Promise或setTimeout的實現,並無Rxjs的實現方式,因此我就用一些操做符實現了這個LazyMan隊列
class LazyManModel { queue: { timeout: number, fn: Function }[] = [] constructor() { setTimeout(() => { from(this.queue).pipe( map(e => { if (e.timeout) return of(e).pipe(delay(e.timeout * 1000)); return of(e) }), concatAll() ).subscribe(value => { value.fn() }) }) } sleep(time: number): this { this.queue.push({ timeout: time, fn: () => { console.log(`Wake up after ${time}`) } }) return this } eat(foot: string): this { this.queue.push({ timeout: null, fn: () => { console.log(`Eat ${foot}~`) } }) return this } sleepFirst(time: number): this { this.queue.unshift({ timeout: time, fn: () => { console.log(`Wake up after ${time}`) } }) return this } exported(): (name: string) => this { return (name): this => { this.queue.push({ timeout: null, fn: () => { console.log(`Hi! This is ${name}!`) } }) return this } } }
示例ip
const LazyMan = new LazyManModel().exported(); LazyMan('Hank').eat('foot').eat('ping').sleep(10).eat('pizza').sleepFirst(5)
我在constructor構造函數裏使用了setTimeout是由於,在調用的時候是鏈式的,其做用域一直都在同一堆棧,而setTimeout裏則是把訂閱的方法放到的最後一個棧執行作用域