面試題 LazyMan 的Rxjs實現方式

_John發表於2019-01-10

前言

筆者昨天在做某公司的線上筆試題的時候遇到了最後一道關於如何實現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~

LazyMan(“Hank”).sleepFirst(5).eat(“supper”)輸出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此類推。

鑑於時間的原因只可惜本人當時並沒寫出來,我當時腦海裡其實看到提意就知道要用到佇列、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
        }
    }
}

示例

const LazyMan = new LazyManModel().exported();
LazyMan(`Hank`).eat(`foot`).eat(`ping`).sleep(10).eat(`pizza`).sleepFirst(5)

關於setTimeout

我在constructor建構函式裡使用了setTimeout是因為,在呼叫的時候是鏈式的,其作用域一直都在同一堆疊,而setTimeout裡則是把訂閱的方法放到的最後一個棧執行

相關文章