实现函数LazyMan,使得:
LazyMan('Hank'); 输出
Hi Hank!
LazyMan('Hank').eat('dinner');输出
Hi Hank!
Eat dinner!
LazyMan('Hank').sleep(5).eat('dinner'); 输出:
Hi Hank!
//等待五秒
Eat dinner!
LazyMan('Hank').sleepFirst(5).eat('dinner');输出:
//等待五秒
Hi Hank!
Eat dinner!
实现函数LazyMan,使得:
LazyMan('Hank'); 输出
Hi Hank!
LazyMan('Hank').eat('dinner');输出
Hi Hank!
Eat dinner!
LazyMan('Hank').sleep(5).eat('dinner'); 输出:
Hi Hank!
//等待五秒
Eat dinner!
LazyMan('Hank').sleepFirst(5).eat('dinner');输出:
//等待五秒
Hi Hank!
Eat dinner!
这道题有点意思,要完成这个任务有点麻烦,我算是稍微取了点巧吧。
我个人是使用了异步来实现的。 Man类内部维护了一个任务队列,所有的类方法都会直接操作任务队列的顺序。
由于类生成时候设定的异步函数必须要等主进程完成之后才会启动,所以它是不会影响到主进程时候的任务队列操作的。
主进程运行结束,类定义时候的setTimeout进程启动,它会把队列中的所有方法用then串联起来,之后任务队列就会按照顺序依次运行了。
当然这还是能随意组合的,比如这样:
LazyMan('Hank').sleepFirst(2).sleep(3).eat('lunch').sleep(4).eat('dinner');
// 等待2秒
// Hi Hank
// 等待3秒
// eat lunch
// 等待4秒
// eat dinner
代码在这里:
function Man(str) {
// 默认函数
function start(resolve) {
console.log(`Hi ${str}`);
resolve();
}
// 初始化队列
this.queue = [start];
setTimeout(() => {
let start = Promise.resolve();
for (let i = 0; i < this.queue.length; i++) {
start = start.then(() => new Promise(this.queue[i]));
}
})
}
Man.prototype.eat = function(food) {
function eatFood(resolve) {
console.log(`Eat ${food}`);
resolve();
}
this.queue.push(eatFood);
return this;
};
Man.prototype.sleep = function(time) {
function sleep(resolve) {
setTimeout(resolve, time * 1000);
}
this.queue.push(sleep);
return this;
};
Man.prototype.sleepFirst = function(time) {
function sleep(resolve) {
setTimeout(resolve, time * 1000);
}
this.queue.splice(0, 0, sleep);
return this;
};
function LazyMan(...args) {
return new Man(...args);
}
赶项目进度中换换脑子,随手试写。可以添加新方法,可以任意组合。感觉写得一般。
LazyMan('Hank').sleepFirst(5).sleep(5).eat('breakfast').sleep(5).eat('lunch').sleep(5).eat('dinner');
function LazyMan(name) {
const lazyMan = {
name,
timer: 0,
firstTimer: 0,
init: false,
handle: function(cb, prop) {
const _this = this;
if(!this.init) {
this.init = true;
if(this.firstTimer > 0) {
setTimeout(function() {
_this.say(_this.name);
}, _this.firstTimer * 1000);
} else {
_this.say(_this.name);
}
}
setTimeout(function() {
cb.call(_this, prop);
}, this.timer * 1000);
},
eat: function(food) {
this.handle(function(food) {
console.log(`Eat ${food}`);
}, food);
return this;
},
sleep: function(timer) {
this.timer += timer;
return this;
},
sleepFirst: function(timer) {
this.timer += timer;
this.firstTimer += timer;
return this;
},
say: function(name) {
console.log(`Hi ${name}`);
return this;
}
}
return lazyMan;
}
前些天看过这个问题,https://www.madcoder.cn/inter...,我把这个大牛写的答案复制到这里。
class C {
constructor (name) {
this.tasks = [];
setTimeout(() => this.next());
return this.push(() => new Promise(r => console.log(`Hi! This is ${name}`) || r()));
}
next () {
let task = this.tasks.shift();
task && task().then(() => this.next());
}
push (v) {
this.tasks.push(v);
return this;
}
unshift (v) {
this.tasks.unshift(v);
return this;
}
sleep (sec) {
return this.push(() => new Promise(r => console.log(`//等待${sec}秒..`) || setTimeout(() => console.log(`Wake up after ${sec}`) || r(), 1000 * sec)));
}
sleepFirst (sec) {
return this.unshift(() => new Promise(r => console.log(`//等待${sec}秒..`) || setTimeout(() => console.log(`Wake up after ${sec}`) || r(), 1000 * sec)));
}
eat (name) {
return this.push(() => new Promise(r => console.log(`Eat ${name}`) || r()));
}
}
const LazyMan = function (name) {
return new C(name);
}
LazyMan('Gcaufy').eat('dinner').sleep(3).eat('supper').sleepFirst(2);
我也来写一个
var lazymen=(function(){
var arr=[];
var i=0;
function next(){
console.log(arr)
if(arr[i]){
arr[i++]();
}else{i=0;arr=[]}
}
var cb=function(fn){
var arg=[].slice.call(arguments,1)
return function(){
fn.apply(null,arg)
}
}
var say=function(x,y){
console.log(x+' '+y);
next()
}
var lazymen=function(str){
arr.push(cb(say,'Hi',str))
setTimeout(function(){
next()
},0)
}
var sleep=function(num){
setTimeout(function(){next()},num*1000)
}
lazymen.prototype.eat=function(str){
arr.push(cb(say,'eat',str))
return this
};
lazymen.prototype.sleep=function(num){
arr.push(cb(sleep,num))
return this
}
lazymen.prototype.sleepFirst=function(num){
arr.unshift(cb(sleep,num))
return this
}
return lazymen
})()
var LazyMan=function(str){
return new lazymen(str)
}
const delay = d => new Promise(resolve => setTimeout(resolve, d))
class LM {
constructor(name) {
this.name = name
this.queue = Promise.resolve()
.then(_ => this.first)
.then(_ => console.log(`Hi ${this.name}`))
}
eat(food) {
this.queue = this.queue.then(_ => console.log(`Eat ${food}`))
return this
}
sleep(d) {
this.queue = this.queue.then(_ => delay(d * 1000))
return this
}
sleepFirst(d) {
this.first = delay(d * 1000)
return this
}
}
function LazyMan(name) {
return new LM(name)
}const LazyMan = function (name) {
let queue = []
const cb = function () {
const fn = queue.shift()
fn && fn()
}
setTimeout(function () {
cb()
})
queue.push(function () {
console.log(`hi ${name}`)
cb()
})
return {
sleep: function (time) {
queue.push(function () {
setTimeout(cb, time * 1000)
})
return this
},
sleepFirst: function (time) {
queue.splice(0, 0, function () {
setTimeout(cb, time * 1000)
})
return this
},
eat: function (food) {
queue.push(function () {
console.log(`eat ${food}`)
cb()
})
return this
}
}
}
LazyMan('alex').sleep(1).eat('?').sleepFirst(2).sleep(2).eat('?')
有点 Promise 的味道,参考了 pinkie 的实现
/**
* https://segmentfault.com/q/1010000008745355
*
* @author Ivan Yan
*/
function Callbacks() {
this.queue = []
this.timer = false
}
Callbacks.prototype.push = function (callback, wait) {
this.queue.push([callback, wait])
if (!this.timer) {
this.timer = true
var next = typeof setImmediate === 'undefined' ? setTimeout : setImmediate
next(this.flush.bind(this), 0)
}
}
Callbacks.prototype.delayAll = function (callback, wait) {
this.queue.unshift([callback, wait])
}
Callbacks.prototype.flush = function () {
while (this.queue.length) {
var item = this.queue.shift()
var wait = item[1]
if (wait) {
setTimeout(this.flush.bind(this), wait)
return
}
item[0]()
}
this.queue = []
this.timer = false
}
function noop() {}
function LazyMan(name) {
if (!(this instanceof LazyMan)) {
return new LazyMan(name)
}
this.name = name
this.callbacks = new Callbacks()
this.hi()
}
LazyMan.prototype._then = function (callback) {
this.callbacks.push(callback)
return this
}
LazyMan.prototype.hi = function () {
var name = this.name
return this._then(function () {
console.log('Hi ' + name)
})
}
LazyMan.prototype.eat = function (sth) {
return this._then(function () {
console.log('Eat ' + sth)
})
}
LazyMan.prototype.sleep = function (s) {
this.callbacks.push(noop, s * 1000)
return this
}
// sleepFirst 延迟了前面的回调 hi
// 问题是延迟前面一个,还是延时前面所有的?
// 这里延时所有的回调
LazyMan.prototype.sleepFirst = function (s) {
this.callbacks.delayAll(noop, s * 1000)
return this
}
// test
// LazyMan('Hank')
// LazyMan('Hank').eat('dinner')
// LazyMan('Hank').sleep(5).eat('dinner')
// LazyMan('Hank').sleepFirst(5).eat('dinner')
// LazyMan('Hank').sleepFirst(2).eat('dinner').sleepFirst(3) // 同上
LazyMan('Hank').sleepFirst(5).eat('launch').sleep(5).eat('dinner')
function Lazy(nick) {
const start = () => {
console.log(`Hello ${this.nick}`)
}
this.nick = nick
this.tasks = []
this.globalTime = 0
this.tasks.push({
run: start
})
setTimeout(() => {
this.tasks.forEach(task => {
task['time'] && (this.globalTime += task.time)
setTimeout((() => {
task['run'] && task.run()
}).bind(this), this.globalTime)
})
})
}
Lazy.prototype.addTask = function(cb, time) {
var lastTask = this.tasks[this.tasks.length - 1]
if (!lastTask['run']) {
lastTask.run = cb
} else {
this.tasks.push({
run: cb,
time: time === undefined ? time : time * 1000
})
}
return this
}
Lazy.prototype.eat = function(str) {
this.addTask(((str) => {
return () => {
console.log(`eat ${str}`)
}
})(str))
return this
}
// 修改前一个task的时延
Lazy.prototype.sleepFirst = function(time) {
var task = this.tasks[this.tasks.length-1]
task.time = time * 1000
return this
}
// 修改后一个任务的时延
Lazy.prototype.sleep = function(time) {
this.tasks.push({
time: this.globalTime + time * 1000
})
return this
}
function LazyMan(nick) {
return new Lazy(nick)
}
今天刚做了这道题,开始有点懵逼,后来才意识到可以基于任务去处理
主要基于以下几点解决问题
1.setTimeout的代码会在执行完其他代码后才执行,并且同时延的基于其先后顺序执行
2.维护任务组遍历执行
3.维护全局时钟用于确定任务的执行时间
缺点:
1.定时器比较多,可以考虑吧更改为setInterval定时轮询
2.子任务使用闭包存储传参,太多了容易内存oom,可以添加到task任务描述上
1 回答851 阅读✓ 已解决
1 回答1.1k 阅读
2 回答773 阅读
2 回答617 阅读
2 回答601 阅读
1 回答681 阅读
2 回答521 阅读
2017-4-12 更新,美化下输出结果。
======================
2017-3-22 代码再次更新,受一道面试题的启发。重新优化了代码(不等待时,setTimeout的间隔时间为0):
得到启发的代码如下:
以下是原答案:
重新来答一遍,这次是认真的,使用了任务队列,同样只使用了一个函数,没用使用Promise,没有使用 timer累加的方法,保证最多只有一个计时器在运行,同时能获取任务开始和最终结束时间。
核心部分是一个 setTimeout 和 一个 任务队列(数组)。
因为使用了队列流程,处理完一个再处理下一个,所以支持多次输出,多次等待,而程序不会乱掉。 LazyMan("A").sleepFirst(1).eat("abc").sleep(4).sleep(5).eat("A").eat("B").eat("C")
测试下结果:
正规作答结束,以下是原答案:
民科解法,欢迎来喷。强迫症,没有使用 任务队列,和 @xiaoboost 答案不同的是,不支持 LazyMan('Hank').sleepFirst(2).sleep(3).eat('lunch').sleep(4).eat('dinner'); 这种方式调用。
不在乎中间过程,只在乎结果。
稍后用队列的方法,重写一遍。