实现一个类,最终效果:
- 可以链式调用
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
*/
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(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')