实现一个 LazyMan 函数
参考:https://blog.csdn.net/qq_39261142/article/details/110425286
1. 描述
- 可以链式调用
sleep()
函数会阻塞后面的链式调用
const lazyMan = new LazyMan('jack') lazyMan.eat('apple').sleep(5000).eat('hamburger').sleep(3000).eat('pear') /* 最终结果: My named jack I am eatting apple I am sleeping... after 5000 ms I am eatting hamburger I am sleeping... after 3000 ms I am eatting pear */
2. 实现
2.1 sleep函数
正常的 sleep 函数,如果是为了链式调用 Promise 可以这样写
function sleep(time) { return new Promise((resolve)=> { setTimeout(() => { resolve() }, time) }) }
但是这里如果为了实现阻塞链式调用而使用 Promise 的方式或者直接延时调用来实现,实际上是一个误区,会给代码增加很多难度,而且还不一定可以实现其功能
class LazyMan { constructor(name) { this.name = name this.task = [] // 任务队列 console.log(`My named ${name}`) } sleep(time) { console.log(`I am sleeping...`) setTimeout(() => { console.log(`after ${time} ms`) return this },time) } eat(food) { console.log(`I am eatting ${food}`) return this } } const lazyMan = new LazyMan('jack') lazyMan.sleep(5000).eat('apple') // property 'eat' of undefined
上面代码中,链式调用并不会主动去阻塞,延时 return this
并不会阻塞链式调用往下进行,因此调用到 eat('apple')
时,由于没有及时的返回 this,自然没有 eat 方法,所以就报错了
这个时候想到 Promise 的实现是用一个任务队列来进行阻塞的,可以也使用这样的方式,与 Promise 不同的是,实现这个并没有那么多的判断条件,只需要将每个任务执行完然后继续执行下一个任务就行
class LazyMan { constructor(name) { this.name = name this.task = [] // 任务队列 console.log(`My named ${name}`) // 这里使用异步调用next()是为了确保所有链式调用都被添加到task[]才开始执行任务 setTimeout(() => { this.next() }) } sleep(time) { this.task.push(() => { console.log(`I am sleeping...`) setTimeout(() => { console.log(`after ${time} ms`) this.next() },time) }) return this } eat(food) { this.task.push(() => { console.log(`I am eating ${food}`) this.next() }) return this } next() { let fn = this.task.shift() fn && fn() // if(fn) fn() } } const lazyMan = new LazyMan('jack') lazyMan.eat('apple').sleep(5000).eat('hamburger').sleep(3000).eat('pear')