在掘金看到的文章,流程控制同步和異步任務的順序執行,收益匪淺,工作中能用到。
1、實現以下效果
實現一個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 supper 以此類推。
這是典型的JavaScript流程控制,問題的關鍵是如何實現任務的順序執行。在Express有一個類似的東西叫中間件,這個中間件和我們這里的吃飯、睡覺等任務很類似,每一個中間件執行完成后會調用next()函數,這個函數用來調用下一個中間件。
對於這個問題,我們也可以利用相似的思路來解決,首先創建一個任務隊列,然后利用next()函數來控制任務的順序執行:
1.2 隊列方式實現
function _LazyMan(name){ this.tasks=[]; var self=this; var fn=(function(n){ var name=n; return function(){ console.log("Hi! this is "+name+"!"); self.next(); } })(name); this.tasks.push(fn); setTimeout(function(){ self.next(); },0); // 在下一個事件循環啟動任務 } /* 事件調度函數 */ _LazyMan.prototype.next=function(){ var fn=this.tasks.shift(); fn && fn(); } _LazyMan.prototype.eat=function(name){ var self=this; var fn=(function(name){ return function(){ console.log("Eat "+name+" ~"); self.next() } })(name); this.tasks.push(fn); return this; // 實現鏈式調用 } _LazyMan.prototype.sleep=function(time){ var self=this; var fn=(function(time){ return function(){ setTimeout(function(){ console.log("Wake up after "+time+" s!"); self.next(); },time*1000); } })(time); this.tasks.push(fn); return this; } _LazyMan.prototype.sleepFirst=function(time){ var self=this; var fn=(function(time){ return function(){ setTimeout(function(){ console.log("Wake up after "+time+" s!"); },time*1000); } })(time); this.tasks.unshift(fn); return this; } /* 封裝 */ function LazyMan(name){ return new _LazyMan(name); }
1.3 promise方式實現
lazyman里邊含有鏈式調用,那么每一個子任務 return this;這個程序支持任務優先順序,那么就需要兩個貫穿全場的Promise對象:第一,普通順序promise;第二,插入順序promise,同時插入順序是阻塞普通順序的,代碼如下:function _LazyMan(name){ this.orderPromise=this.newPromise(); // 定義順序promise對象 this.insertPromise=this.newPromise(); // 定義插入promise對象 this.order(function(resolve){ console.log(name); resolve(); }) } _LazyMan.prototype={ /*實例化promise對象工廠*/ newPromise:function(){ return new Promise(function(resolve,reject){ resolve(); }) }, order:function(fn){ var self=this; this.orderPromise=this.orderPromise.then(function(){ return new Promise(function(resolve,reject){ //如果有insertPromise,阻塞orderPromise. self.fir?self.insertPromise.then(function(){ fn(resolve) }):fn(resolve) }) }) }, insert:function(fn){ var self=this; this.fir=true; this.insertPromise=this.insertPromise.then(function(){ return new Promise(function(resolve,reject){ fn(resolve); self.fir=false; }) }) }, sleepFirst:function(time){ this.insert(function(resolve){ setTimeout(function(){ console.log('wait '+time+' s,other logic'); resolve(); },time*1000) }) return this; }, eat:function(something){ this.order(function(resolve){ console.log(something+' ~~'); resolve(); }) return this; }, sleep:function(time){ this.order(function(resolve){ setTimeout(function(){ console.log('sleep '+time+' s'); },time*1000); }) return this; } } //接口封裝。 function LazyMan(name) { return new _LazyMan(name); } //調用測試 LazyMan(‘RoryWu‘).firstTime(1).sleep(2).firstTime(3).eat(‘dinner‘).eat(‘breakfast‘); // 彈出: // wait 1 s, other logic // wait 3 s, other logic // RoryWu // sleep 2 s // dinner~~ // breakfast~~
原文地址:https://juejin.im/post/59c0da1f5188252c24747715
