首先請看網友通過setTimeout實現的: 分析: 用setTimeout模擬線程,有一個事件處理隊列(this.tasks),然後每一個事件內部會調用事件調度函數(next),每一次的業務邏輯是通過定義的閉包函數fn,fn內部在處理完自身業務會執行next函數。 於是就想起處理這種含有非同步並且有 ...
首先請看網友通過setTimeout實現的:
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!"); self.next(); }, time * 1000); } })(time); this.tasks.unshift(fn); return this; } /* 封裝 */ function LazyMan(name){ return new _LazyMan(name); } LazyMan('Hank').sleepFirst(5).sleep(10).eat('dinner')
分析:
用setTimeout模擬線程,有一個事件處理隊列(this.tasks),然後每一個事件內部會調用事件調度函數(next),每一次的業務邏輯是通過定義的閉包函數fn,fn內部在處理完自身業務會執行next函數。
於是就想起處理這種含有非同步並且有一定阻塞的業務,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; }) }) }, firstTime: 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'); resolve() }, 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~~
註意每一個任務的業務邏輯都是通過回調函數的形式實現的,內部擁有兩種API:
1 this.order(function(){ ... })
2 this.insert(function() {... })
這裡的核心需要註意以下幾點:
1 每一次任務的業務邏輯函數,就是這個回調函數傳給對應的API,執行場地在它那。
2 每一個API的執行權利交給任務函數自身,是通過參數傳遞的方式,例如: fn(resolve),每一個任務函數在執行完自身業務邏輯後,通過resolve()改變Promise對象狀態為Resolved(其他:rejected pending).
3 連個API的優先順序實現,通過一個this.fir的狀態值來判斷是否含有插入promise對象,如果有就,就做一件事情改變fn發生的時間: insertPromise.then(function(){ fn(resolve) })
通過上邊的實現,最後總結一下,在設計程式的時候,首先想想程式的大概構成,然後在開始寫,這樣大思路不會跑,進而很快就寫出來了。