字节一面出了一道好题:实现一个异步链式调用的效果:new CodeMan().eat("lunch").sleep(10).eat("dinner")
。sleep(10)
表示要异步地等待10s以后执行后面的内容。
面试官只给了一个关键字的提示:队列。我是那个百思不得其解啊!
面试后,我想了想,调用阶段(是同步任务,会先执行)先用一个队列把任务收集起来(这里把eat和sleep统称为”任务“),然后用”宏任务在同步任务执行完以后才执行“这个特性,来搞一个”假递归“,即当前任务执行完后再把下一个任务扔进宏任务队列。
而第一个任务,用setTimeout(process,0)
调用,因为以上特性,所以它会在收集完毕以后才执行。
于是我们抽象出一个process函数,它的工作是:执行当前的宏任务。
更新:发出文章后看到前人的实现,感觉比我这个做法复杂些……
代码
function CodeMan(){
let EAT = Symbol(),SLEEP = Symbol()
function Task(type,arg){
this.type = type
if(type === EAT) this.food = arg
else this.time = arg
}
let q = []
this.eat = (food) => {
q.push(new Task(EAT,food))
return this
}
this.sleep = (time) => {
q.push(new Task(SLEEP,time*1000))
return this
}
let process = () => {
if(!q.length) return
let u = q.shift()
if(u.type === EAT){
console.log(u.food)
setTimeout(process,0)
}
else{
setTimeout(process,u.time)
}
}
setTimeout(process,0)
}
new CodeMan().eat("lunch").sleep(2).eat("dinner").sleep(2).eat('breakfast')