牛客网看到的一道腾讯实习笔试题
发布于 1 年前 作者 Littlesqx 2786 次浏览 来自 问答

实现 Hardman 函数

要求:

HardMan("jack") 
// > I am jack

HardMan("jack").rest(10).learn("computer")
// > I am jack
// 等待10秒
// > Start learning after 10 seconds
// > Learning computer

HardMan("jack").restFirst(5).learn("chinese")
// 等待5秒
// > Start learning after 5 seconds
// > I am jack
// > Learning chinese

上文中 [ > … ] 表示打印内容。

挺有意思的,但是解不了,就来问问

13 回复
function HardMan(name) {
  function introduce() {
    console.log(`I am ${name}`)
  }
  let first = 0
  let delay = 0
  let timer = setTimeout(introduce, 0)
  return Object.create({
    rest(time) {
      delay += time * 1000
      return this
    },
    restFirst(time) {
      clearTimeout(timer)
      first += time * 1000
      timer = setTimeout(function () {
        console.log(`Start learning after ${time} seconds`)
        console.log(`I am ${name}`)
      }, first)
      return this
    },
    learn(lessen) {
      setTimeout(function () {
        console.log(`Learning ${lessen}`)
      }, delay + first)
      return this
    }
  })
}

以上代码可以实现当前要求 推测考察的是对eventloop的理解吧 但是restrestFirst如果多次调用就不知道了 要求里没有体现

刚写完,发现楼上已经发出答案了。比自己写的简单多了。就不贴代码了。向楼上学习。

@Zero2key 考什么我就不知道了,不过你的答案能实现要求就是了。我也贴一下找到的另一个答案,可以实现多次 rest

const HardMan = function (name) {

    this.tasks = [
        () => console.log(`I am ${name}`)
    ];

    this.rest = function (time) {
        this.tasks.push(this.sleep(time));
        return this;
    }
    this.restFirst = function (time) {
        this.tasks.unshift(this.sleep(time));
        return this;
    }
    this.learn = function (something) {
        this.tasks.push(() => console.log('Learning ' + something));
        return this;
    }
    this.sleep = function (time) {
        return () => new Promise(resolve => setTimeout(() => {
            resolve(console.log(`Start learning after ${time} second`));
        }, time * 1000));
    }
    this.run = function () {
        setTimeout(async () => {
            for (task of this.tasks) {
                await task();
            }
        }, 0);
        return this;
    }
    return this.run();
}

@hfuuss 也学习一下这个。

function HardMan(name) {
    var tasks = [];
    var after = 0;
    var next = function () {
        if (tasks.length) (tasks.shift())();
    };
    var sleep = function (time) {
        return function () {
            setTimeout(function () {
                after += time;
                console.log(`Start learning after ${after} second`);
                next();
            }, time * 1000);
        };
    };
    var fn = function () { };

    fn.prototype.rest = function (time) {
        tasks.push(sleep(time));
        return this;
    };
    fn.prototype.restFirst = function (time) {
        tasks.unshift(sleep(time));
        return this;
    };
    fn.prototype.learn = function (subject) {
        tasks.push(function () {
            console.log(`Learning ${subject}`);
            after = 0;
            next();
        });
        return this;
    };

    tasks.push(function () {
        console.log(`I am ${name}`);
        after = 0;
        next();
    });

    setTimeout(next, 0);

    return new fn();
}
HardMan("jack").rest(2).learn("chinese").rest(3).learn("computer").restFirst(1);
let HardMan = function(name){

	let firstRestTime = false, restTime = false, theThing = '';
	function C(e){ console.log(e); }

	setTimeout(()=>{
		if(firstRestTime === 0 || firstRestTime){
			setTimeout(()=>{
				C('Start learning after '+ firstRestTime +' seconds');
				C('I am '+name);
				C('Learning ' + theThing);
			},firstRestTime * 1000);
		}else if(restTime === 0 || restTime){
			C('I am ' + name);
			setTimeout(()=>{
				C('Start learning after '+restTime+' seconds');
				C('Learning '+ theThing);
			},restTime * 1000);
		}else{
			C('I am '+name);
		}
	},0);


	return {
		rest(time){
			restTime = time;
			return this;
		},
		learn(thing){
			theThing = thing;
			return this;
		},
		restFirst(time){
			firstRestTime = time;
			return this;
		}
	}
}

var HardMan = function (name) {

        var promise = function (timer, text) {
            return new Promise((resolve, reject) => {
                if (timer) {
                    setTimeout(() => {
                        resolve(text);
                    }, timer);
                    return;
                }

                reject(text);
            });
        };

        class Foo {
            constructor(name) {
                this.name = name;
                this.delay = 0;
                this.result = [];

                this.result.push({ time: this.delay, text: `I am ${name}` });

                setTimeout(() => {
                    var isTime = 0;

                    this.result.forEach(item => {
                        isTime = item.time || isTime;

                        promise(item.time || isTime, item.text)
                            .then(console.log)
                            .catch(console.log);
                    });

                }, 0);
            }

            rest(time) {
                this.delay = time * 1000;
                this.result.push({ time: this.delay, text: `Start learning after ${time} seconds` });
                return this;
            }

            learn(name) {
                this.result.push({ time: this.delay, text: `Learning ${name}` });
                return this;
            }

            restFirst(time) {
                this.delay = time * 1000;
                this.result.unshift({ time: this.delay, text: `Start learning after ${time} seconds` });
                return this;
            }
        }

        return new Foo(name);
    };

aop 切片 实现

@Littlesqx 这个思路是对的,正如六楼要的----最后还能restFirst,所以是用一个任务队列来存储这些调用。 首先构造函数把介绍自己的任务压入队列,然后在下一个事件循环开始时,取出并执行队列第一个任务。 每一个方法都会把”自己的功能+调用队列下一个任务“包装成任务,压入队列中。有点像restify中间件的调用。 值得说的是restfirst方法需要把任务弄到队列头部。

贴出我自己写的有注释版本:

function HardMan(name) {
	var Man = function (name) {
		// 存自己的名字
		this.name = name
		// 任务队列
		this.queue = []
		// 把介绍自己的方法入列
		this.me()
		// 下个事件循环开始调用队列
		setTimeout(() => {
			this.callNext()
		}, 0)
	}
	
	Man.prototype = {
	    // 取出队列顶部函数,调用
		callNext: function() {
			if(this.queue.length)
			this.queue.shift()()
		},
		// 介绍自己,普通任务,
		me: function () {
			var ii = () => {
					console.log('I am ' + this.name)
					this.callNext()
			}
			this.queue.push(ii)
		},
		// 休息,直接把延时函数压入队列,定时结束后再调用队列下一个任务
		rest: function(sec) {
			var ii = () => {
				setTimeout(()=>{
					console.log(`after ${sec} secs`)
					this.callNext()
				}, sec * 1000)
			}
			this.queue.push(ii)
			return this
		},
		// 同理,只是任务放到队列顶部,
		restFirst: function(sec) {
			var ii = () => {
				setTimeout(()=>{
					console.log(`after ${sec} secs`)
					this.callNext()
				}, sec * 1000)
			}
			this.queue.unshift(ii)
			return this
		},
		// 普通任务
		learn: function(course) {
			var ii = () => {
					console.log(`learn ${course}`)
					this.callNext()
			}
			this.queue.push(ii)
			return this
		}
	}
	Man.prototype.constructor = Man
	return new Man(name)
}

HardMan("jack").rest(2).learn("chinese").rest(3).learn("computer").restFirst(1)

看来只有我想复杂了。。。用的promise来实现,原来一个队列就可以解决的事

一个简洁的实现,支持随意重复调用rest/restFirst/learn(把restart也放进去只是为了让后面少一行代码)

function HardMan (name) {
  const sleep = sec => new Promise(res => setTimeout(res, sec * 1000));
  const queue = [() => console.log(`I am ${name}`)];
  let timer;
  return Object.create({
    restart() {
      clearTimeout(timer);
      timer = setTimeout(() => queue.reduce((p, t) => p.then(t), Promise.resolve()));
      return this;
    },
    rest(time) {
      queue.push(async () => sleep(time));
      return this.restart();
    },
    restFirst(time) {
      queue.unshift(async () => (await sleep(time)) || console.log(`Start learning after ${time} second`));
      return this.restart();
    },
    learn(sth) {
      queue.push(() => console.log(`Learning ${sth}`));
      return this.restart();
    },
  });
}

景安拼团活动,云服务器96元/年。原价960 活动链接:http://server.zzidc.com/pintuan.html

回到顶部