在掘金看到的文章,流程控制同步和異步任務的順序執行,收益匪淺,工做中能用到。promise
實現一個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()函數來控制任務的順序執行:函數
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); }
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~~