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
以此类推。
Lazy man named Tom was born!
Tom sleep 3 seconds at first!
Tom eat apple!
Tom eat dinner!
Tom sleep 1 seconds!
Tom eat Ball!
Tom don't want to do anything.
// 增加tired字段
constructor (name) {
this.name = name;
this.taskList = [];
this.tired = false;
console.log(`Lazy man named ${name} was born!`);
}
// 一般任务方法:
eat (what) {
let task = new LazymanTask({
ignore: this.tired,
action: () => {
console.log(this.name + ' eat ' + what + '!');
this.next();
}
});
this.taskList.push(task)
return this;
}
// break方法:
break () {
let task = new LazymanTask({
ignore: this.tired,
action: () => {
console.log(`${this.name} don't want to do anything.`);
this.taskList = [];
}
});
this.taskList.push(task);
this.tired = true;
return this;
}
// next方法:
next () {
this.taskList = this.taskList.filter(val => !val.ignore);
if (this.taskList.length > 0) {
this.taskList.shift().action();
}
return this;
}
运行下列代码:
lazyman('Tom')
.eat('dinner')
.sleep(1)
.eat('Ball')
.break()
.sleep(2)
.eat('huaji')
.sleepFirst(3)
.next();
// ->结果
Lazy man named Tom was born!
Tom eat dinner!
Tom sleep 1 seconds!
Tom eat Ball!
Tom don't want to do anything.
看来还是有效的。
更新: 实现doLast
思路:
last的列表不能被污染,必须放到队列最尾。
做法:
Lazyman类中加入另一个task列表:lastTask
如果使用doLast类型的方法加入任务,则插入到改列表中。
运行时,将lastTask合并至taskList,然后清空taskList。
最后和原来一样按序执行taskList就可以了。
代码:
// 增加lastTask列表
constructor (name) {
this.name = name;
this.taskList = [];
this.lastTask = [];
this.tired = false;
console.log(`Lazy man named ${name} was born!`);
}
// doLast类型的方法
eatLast (what) {
let task = new LazymanTask({
ignore: this.tired,
action: () => {
console.log(this.name + ' eat ' + what + '!');
this.next();
}
});
this.lastTask.push(task)
return this;
}
// next方法:
next () {
if (this.lastTask.length > 0) {
this.taskList = this.taskList.concat(this.lastTask);
this.lastTask = [];
}
this.taskList = this.taskList.filter(val => !val.ignore);
if (this.taskList.length > 0) {
this.taskList.shift().action();
}
return this;
}
运行就略了。
更新:实现代码串最后省略.next
实现起来很简单,先放结论:
构造函数中最后增加一行代码:
constructor (name) {
this.name = name;
this.taskList = [];
this.lastTask = [];
this.tired = false;
console.log(`Lazy man named ${name} was born!`);
setTimeout(() => this.next(), 0); // 这里
}
lazy man的实现
原题
之前微信的面试题,实现一个lazyman,要求创建一个lazyman之后,输入一串指令,结束后lazy按次序执行。
原题似乎是这样的:(抄自LazyMan的深入解析和实现 - 简书 - wall_wxk)
初步实现
因为一般而言,调用某方法的话,会立刻执行方法中的函数。但是此题需要输入完所有方法再延迟执行,因此需要建立一个队列,最后输入完任务,执行队列。
我的实现(以下代码可复制到较新版chrome浏览器中直接执行):
核心就是,每次命令lazyman做事时,将做的事插入到队列taskList最后端,如果是要首先去做的事(doFirst),就插入到队列最前端。
并且做的事中都要再次调用
next
方法,确保有事可做时,会一直做到最后。命令输入完毕时,执行
.next
,顺序执行。注意的几点
返回this
的链式调用next
方法可以起到delay的作用。pop
,push
,shift
,unshift
的异同反思
有几点我不满意:
.next()
,手动开始。能不能不用这条语句,lazyman自动检测队列输入完毕?.doLast()
,最后执行的,应该怎么做?.break()
,执行到这一步,lazyman不想做后面的事了,应该怎么办?console.log
最好抽象出方法。因为lazyman的输出可能会改变,到时候代码中的每句console.log都去改就太麻烦了。更新:实现break
于是马上实现了下
break
:执行后:
确实中断了队列后面的任务。
可惜无法中断
doFirst
的任务。因为doFirst任务会插在队列头部。要实现也可以,一种方法是将
任务
抽象出类,需要包含一个是否丢弃的boolean值。默认为false,一旦调用break,后面新增的task任务都改为true(要丢弃),next的时候不执行。Lazyman的改动:
运行下列代码:
看来还是有效的。
更新: 实现doLast
思路:
last的列表不能被污染,必须放到队列最尾。
做法:
Lazyman类中加入另一个task列表:
lastTask
如果使用doLast类型的方法加入任务,则插入到改列表中。
运行时,将
lastTask
合并至taskList
,然后清空taskList。最后和原来一样按序执行
taskList
就可以了。代码:
运行就略了。
更新:实现代码串最后省略
.next
实现起来很简单,先放结论:
构造函数中最后增加一行代码:
请注意,setTimeout函数中需要用把
this.next()
放到箭头函数内。只有放到箭头函数内,this才可以直接取到当前Lazyman对象。若需要用es5形式,则应加闭包,把环境this传进去:
闭包问题不再细说。
运行
lazyman('Tom').eat('dinner').sleep(1).eat('Ball')
:我们没有在执行链最后加
next
,而是放到构造函数中,就成功了。但是为何用
setTimeout(fn, 0)
的形式呢?此处那就是下一个话题了。