LazyMan问题

分享一道面试题:
实现一个LazyMan,能够按照如下方式调用:
LazyMan("Hank")输出:
Hi! This is Hank!

LazyMan("Hank").sleep(10).eat("dinner")输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

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 suppernode

以此类推。面试

涉及到的技术点:
链式编程
JS流程控制
JS事件循环机制Promise
。。。编程

方法1:
问题的关键是如何实现任务的顺序执行。
参考node.js,在Express有一个相似的东西叫中间件,这个中间件和咱们这里的吃饭、睡觉等任务很相似。
每个中间件执行完成后会调用next()函数,这个函数用来调用下一个中间件。
对于这个问题,咱们也能够利用类似的思路来解决。
首先建立一个任务队列,而后利用next()函数来控制任务的顺序执行:
[JavaScript] 纯文本查看 复制代码
?promise

function LazyMan(name) {app

// 建立一个任务队列
let taskList = [];
// 建立lazyman对象
let _lazyMan = {
    // 执行下一步 的方法
    next() {
        // 抽取任务队列中的第一个任务
        let task = taskList.shift();
        // 若是存在该任务,就调用该任务
        task && task()
    },
    // sayHi(打招呼) 方法
    sayHi(name) {
        // 在任务队列 最后面 追加任务
        taskList.push(() => {
            // 打招呼
            console.log(`Hi! This is ${name}!`);
            // 该任务完成以后,调用下一步的方法
            this.next()
        })
        // return this 为了实现链式编程
        return this
    },
    // sleep(睡觉) 方法
    sleep(time) {
        // 在任务队列 最后面 追加任务
        taskList.push(() => {
            // 开启定时器
            setTimeout(() => {
                // 输入 多少秒以后醒来
                console.log(`Wake up after ${time}`);
                // 该任务完成以后,调用下一步的方法
                this.next()
            }, time * 1000);
        })
        // return this 为了实现链式编程
        return this
    },
    eat(food) {
        taskList.push(() => {
            console.log(`Eat ${food}~`);
            this.next()
        })
        return this
    },
    // sleepFirst(先睡) 方法
    sleepFirst(time) {
        // 在任务队列 最前面 添加任务
        taskList.unshift(() => {
            // 开启定时器
            setTimeout(() => {
                console.log(`Wake up after ${time}`);
                // 该任务完成以后,调用下一步的方法
                this.next()
            }, time * 1000);
        })
        // return this 为了实现链式编程
        return this
    }
}

// 手动调用 sayHi方法
_lazyMan.sayHi(name)
// 使用定时器,让任务队列在同步线程完成以后再执行
setTimeout(() => {
    _lazyMan.next()
}, 0);
// 暴露 lazyman对象
return _lazyMan

}函数

// LazyMan("Hank")
// LazyMan("Hank").sleep(5).eat("dinner")
// LazyMan("Hank").eat("dinner").eat("supper")
LazyMan("Hank").sleepFirst(5).eat("supper")this

方法2:prototype

  1. 看题目输出示例,能够肯定这是拟人化的输出,也就是说:应该编写一个类来定义一类人,叫作LazyMan。能够输出名字、吃饭、睡觉等行为。

 2. 从输出的句子能够看出,sleepFrist的优先级是最高的,其余行为的优先级一致。
 3. 从三个例子来看,都得先调用LazyMan来初始化一我的,才能继续后续行为,因此LazyMan是一个接口。
 4. 句子是按调用方法的次序进行顺序执行的,是一个队列。线程

[JavaScript] 纯文本查看 复制代码
?code

// 采用模块模式来编写代码
(function (window, undefined) {

// 建立一个任务队列
var taskList = [];
// {
//     'msg': 'LazyMan', // 消息名
//     'args': 'Hank'    // 参数列表
// }
// 订阅
function subscribe() {
    var args = Array.prototype.slice.call(arguments);

    if (args.length < 1) {
        throw new Error("subscribe 参数不能为空!");
    }
    // 建立任务
    var task = {
        msg: args[0], // 消息名
        args: args.slice(1) // 参数列表
    }

    // 除非是 sleepFirst 向前添加,不然向后追加
    if (task.msg == "sleepFirst") {
        taskList.unshift(task);
    } else {
        taskList.push(task);
    }
}

// 发布
function publish() {
    if (taskList.length > 0) {
        // 调用 run(执行)方法
        run(taskList.shift());
    }
}

// 类
function LazyMan() {};

LazyMan.prototype.eat = function (str) {
    subscribe("eat", str);
    return this;
};

LazyMan.prototype.sleep = function (num) {
    subscribe("sleep", num);
    return this;
};

LazyMan.prototype.sleepFirst = function (num) {
    subscribe("sleepFirst", num);
    return this;
};

// 输出文字
function lazyManLog(str) {
    console.log(str);
}

// 具体方法
// 打招呼
function lazyMan(str) {
    lazyManLog("Hi!This is " + str + "!");
    publish();
}
// 吃
function eat(str) {
    lazyManLog("Eat " + str + "~");
    publish();
}
// 睡
function sleep(num) {
    setTimeout(function () {
        lazyManLog("Wake up after " + num);

        publish();
    }, num * 1000);

}
// 先睡
function sleepFirst(num) {
    setTimeout(function () {
        lazyManLog("Wake up after " + num);

        publish();
    }, num * 1000);
}

// run(执行)方法:
function run(option) {
    var msg = option.msg,
        args = option.args;

    switch (msg) {
        case "lazyMan":
            lazyMan.apply(null, args);
            break;
        case "eat":
            eat.apply(null, args);
            break;
        case "sleep":
            sleep.apply(null, args);
            break;
        case "sleepFirst":
            sleepFirst.apply(null, args);
            break;
        default:
            ;
    }
}

// 暴露接口
window.LazyMan = function (str) {
    subscribe("lazyMan", str);

    setTimeout(function () {
        publish();
    }, 0);

    return new LazyMan();
};

})(window);

// LazyMan("Hank")
// LazyMan("Hank").sleep(5).eat("dinner")
// LazyMan("Hank").eat("dinner").eat("supper")
LazyMan("Hank").sleepFirst(5).eat("supper")

Promise版:
[JavaScript] 纯文本查看 复制代码
?

function _LazyMan(name) {

this.promiseGetters = [];

var makePromise = function  () {
    var promiseObj = new Promise(function(resolve, reject){
        console.log("Hi! This is " + name + "!");

        resolve();
    })

    return promiseObj;
}

this.promiseGetters.push(makePromise);

// 在各个Promise的then函数中,将任务序列穿起来
var self = this;
var sequence = Promise.resolve();
// Promise.resolve 等价于
// var sequence = new Promise(function (resolve, reject) {
//     resolve();
// })
setTimeout(function(){
    for (var i = 0; i < self.promiseGetters.length; i++) {
        var nowPromiseGetter = self.promiseGetters[i];
        var thenFunc = (function (nowPromiseGetter) {
            return function  () {
                return nowPromiseGetter()
            }
        })(nowPromiseGetter);

        sequence = sequence.then(thenFunc);
    };

}, 0); // 在下一个事件循环启动任务

}

_LazyMan.prototype.eat = function(name) {

var makePromise = function  () {
    var promiseObj = new Promise(function(resolve, reject){
        console.log("Eat " + name + "~");

        resolve();
    })

    return promiseObj;
}

this.promiseGetters.push(makePromise);

return this; // 实现链式调用

}

_LazyMan.prototype.sleep = function(time) {

var makePromise = function  () {
    var promiseObj = new Promise(function(resolve, reject){

        setTimeout(function(){

            console.log("Wake up after " + time + "s!");

            resolve();

        }, time * 1000);
    })

    return promiseObj;
}

this.promiseGetters.push(makePromise);

return this;

}

/ 封装 /

function LazyMan(name){

return new _LazyMan(name);

}

LazyMan("Hank").sleep(1).eat("dinner")更多技术资讯可关注:gzitcast

相关文章
相关标签/搜索