每日一题:
实现一个类,其实例可以链式调用,他有一个sleep方法,可以sleep一段时间后再后续调用
const boy = new PlayBoy('Tom') boy.sayHi().sleep(1000).play('王者').sleep(2000).play('跳一跳')
// 输出
// 大家好我是Tom
// 1s 之后
// 我在玩王者
// 2s 之后
// 我在玩跳一跳
方案一:思路(阻塞式解决方案)
- 根据时间进行判断执行
- 主要是while循环强制主线程执行此环节,while是同步代码。所以后续代码的执行会出现阻塞现象。
class PlayBoy {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`大家好我是${this.name}`);
return this;
}
play(game) {
console.log(`我在玩${game}`);
return this;
}
sleep(time) {
const start = new Date().getTime();
while (new Date().getTime() < start + time) {
}
console.log(`${time/1000}s 之后`);
return this
}
}
const boy = new PlayBoy("Tom");
boy.sayHi().sleep(1000).play("王者").sleep(2000).play("跳一跳");
方案二:思路(异步调用解决方案)
- 主线程不阻塞
- 虽然无法按照题目规定完成算法要求,但是也是一种无阻塞的办法实现,可以无缝
- 主要是将sleep函数包裹成一个Promise
- 此方案主要三实现思路过渡
class PlayBoy{
constructor(name){
this.name = name;
}
sayHi = ()=>{
console.log(this.name);
return this
}
sleep = (tiemTag)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(this)
},tiemTag*1000)
})
}
play(doing){
console.log(doing);
return this;
}
}
const boy = new PlayBoy("Tom");
boy.sayHi().sleep(2).then(async (that)=>{
let body = that.play("打篮球");
let result = await that.sleep(3);
body = result.play("游泳");
result = await that.sleep(2);
body = result.play("回家");
});
console.log("主线程不阻塞");
思路三:(异步调用队列解决方案)
在看懂思路二的基础上,在想一种办法,即异步队列,思路二作为异步概念的强调,继承于思路二,如果将异步方法放入一个队列当中,按队列顺序进行执行。即可以实现不阻塞主线程的情况下顺序执行异步队列的方法!
demo1:(经验证此方法无法实现异步队列的顺序执行)
let queue = [new Promise((resolve)=>{
setTimeout(()=>{
console.log("a");
resolve()
},4000)
}),new Promise((resolve)=>{
setTimeout(()=>{
console.log("b");
resolve()
},3000)
})];//异步队列
async function run(){
for(let i=0;i<queue.length;i++){
if(typeof queue[i] === 'function'){
queue[i]();
}else{
if(queue[i] instanceof Promise){
let result = await queue[i];
console.log(result);
}
}
}
}
run();//遍历异步队列。发现无法实现顺序遍历
demo2:主线程不阻塞的顺序遍历异步队列
const createPromise = (id) => () =>{
return new Promise(resolve=>
setTimeout(()=>{
console.log("promise->"+id+":"+new Date());
resolve();
},1000*id)
)
}
var tasks = [createPromise(1),createPromise(4),createPromise(3)];
console.log(tasks);
var doTask = tasks.reduce((prev,next)=>prev.then(()=>{
return next()
}),Promise.resolve());
console.log('主线程不阻塞');
这里比较难以理解的是两个地方,createPromise将返回一个匿名函数,此匿名函数如果执行将会返回一个Promise。从而达到我想要的目的;
数组方法:reduce!!!。一个被我玩坏的函数,这个函数此刻的作用就是作为启动异步队列的实现,我首先将prev只作为Promise,顺序执行过程中,通过。.then
函数触发,内部下次启动任然是返回一个next()执行后的Promise!!!!。从而达到异步队列的顺序执行,
- 理解了以上步骤,从而实现了异步方法队列的调用成功,就可以运用到此算法实例中即可。
class PlayBoy {
constructor(name) {
this.name = name;
this.queue = [];
this.games = [];
}
sayHi() {
this.queue.push(() => {
console.log(`大家好,我是${this.name}`);
});
return this; // 返回实例,以便链式调用
}
sleep(time) {
this.queue.push(this.createPromise(time));
return this; // 返回实例,以便链式调用
}
play(game) {
this.games.push(game)
return this; // 返回实例,以便链式调用
}
start() {
this.queue.reduce((prev,next)=>prev.then(()=>{
return next()
}),Promise.resolve());
}
createPromise = (time) => () =>{
return new Promise(resolve=>
setTimeout(()=>{
console.log(this.games.shift());
resolve();
},1000*time)
)
}
}
const boy = new PlayBoy('Gege');
boy.sayHi().sleep(2).play("唱").sleep(3).play('跳').sleep(1).play('rap').start();
按顺序时间输出:
大家好,
我是Gege
唱
跳
rap