Open fi3ework opened 6 years ago
学习了
可以把任务看成三类:sleepFirst(微任务)、sayname(constructor任务)、eat&sleep(宏任务) 整个过程就是: 先串行执行微任务,再执行constructor任务,最后串行执行宏任务
class LazyMan {
constructor(name) {
this.name = name;
this.microTaskList = []; // 微任务
this.macroTaskList = []; // 宏任务
// Promise.resolve()使得先注册回调 再执行constructor
Promise.resolve()
.then(() => this.runInOrder(this.microTaskList))
.then(() => this.sayHello())
.then(() => this.runInOrder(this.macroTaskList));
}
sleepFirst(time) {
this.taskListAdd({type: 'micro', funcType: 'sleepFirst', params: {time}});
return this;
}
sleep(time) {
this.taskListAdd({type: 'macro', funcType: 'sleep', params: {time}});
return this;
}
eat(food) {
this.taskListAdd({type: 'macro', funcType: 'eat', params: {food}});
return this;
}
sayHello() {
console.log(`Hi This is ${this.name}`);
}
runInOrder(promiseArr) {
return promiseArr.reduce(
(prevPromise, nextPromise) => prevPromise.then(() => nextPromise()),
Promise.resolve()
);
}
taskListAdd({type, funcType, params}) {
let func = () => {};
switch (funcType) {
case 'sleep':
case 'sleepFirst':
func = () => new Promise(resolve => {
setTimeout(() => {
console.log(`Wake up after ${params.time}`);
resolve();
}, params.time * 1000);
});
break;
case 'eat':
func = () => new Promise(resolve => {
console.log(`Eat ${params.food}~`);
resolve();
});
break;
default:
break;
}
this[`${type}TaskList`].push(func);
}
}
这是我想到的版本,看到这个题目,我没有自己去写任务队列,而是使用了系统级别的宏任务和微任务
class LazyMan {
constructor(name) {
this.name = name;
setTimeout(() => {
console.log("Hi! This is " + name);
}, 0);
}
sleep(seconds) {
const delay = seconds * 1000;
const time = Date.now();
while (Date.now() - time < delay) {
// hu lu lu ~~
}
setTimeout(() => {
console.log("wake up after " + seconds);
}, 0);
return this;
}
eat(something) {
setTimeout(() => {
console.log("eat " + something);
}, 0);
return this;
}
sleepFirst(seconds) {
new Promise((resolve) => {
const delay = seconds * 1000;
const time = Date.now();
while (Date.now() - time < delay) {
// hu lu lu ~~
}
resolve();
}).then(() => {
console.log("wake up after " + seconds);
});
return this;
}
}
function lazyMan(name) {
return new LazyMan(name);
}
lazyMan("Hank").sleep(2).eat("dinner").sleepFirst(3);
function lazyMan (name) {
const tasks = []
const methods = {
say(name) {
tasks.push(() => console.log(`Hi! This is ${name}`))
return this
},
eat(food) {
tasks.push(() => console.log(`Eat ${food}`))
return this
},
sleepFirst(time) {
tasks.unshift(() => new Promise(resolve => setTimeout(resolve, time * 1000)))
return this
},
sleep(time) {
tasks.push(() => new Promise(resolve => setTimeout(resolve, time * 1000)))
return this;
}
}
setTimeout(function run() {
if(!tasks.length) return
Promise.resolve(tasks.shift()()).then(run)
}, 0)
methods.say(name)
return methods
}
// lazyMan('think2011').sleep(3).eat('supper')
// lazyMan('think2011').eat('dinner').eat('supper')
lazyMan('think2011').sleepFirst(3).eat('supper')
我来一个不使用 class 的
题目
实现一个 LazyMan,可以按照以下方式调用:
LazyMan("Hank")
输出:
LazyMan("Hank").sleep(10).eat("dinner")
输出:
等待10秒..
LazyMan("Hank").eat("dinner").eat("supper")
输出:
LazyMan("Hank").sleepFirst(5).eat("supper")
等待5秒
实现
1. callback
纯 callback 实现, 每个注册的事件的最后会调用对象队列中的下一个事件。
2. Promise
手工在每次方法执行后通过 then 调整 Promise 链的序列,缺点是因为 sleepFirst 要强行插入 Promise 链的第一位,要单独抽象出一部分逻辑来前置它的 Promise。
3. Promise + 队列
在对象内部维护一个队列,让所有的事件都变成异步的,然后在内部通过 Promise.resolve.then() 来将队列的执行启动推迟到下一个 eventloop,这样做逻辑更清楚,所有事件都由队列来管理。
4. Promise + async
基本思路与第 2 种方法相同,不同的地方只在于使用了 async 来顺序执行队列。
TODO
总结
整个过程其实还挺有意思的,多写几种方法挺练 Promise 和整个异步调用的思维的..