笔者昨天在作某公司的线上笔试题的时候遇到了最后一道关于如何实现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里则是把订阅的方法放到的最后一个栈执行作用域