等待者模式
等待者模式是通過對多個異步任務進行監聽,當異步任務完成後觸發未來發生的動作,在沒有
Promise
這個模型的時候,其實就已經出現這樣類似的技術方案,不同的隻是沒有定制為一個技術規範,等待者模式不屬于一般定義的
23
種設計模式的範疇,而通常将其看作廣義上的技巧型設計模式。
描述
等待者模式就是通過對異步程序監聽,來觸發未來發生的動作,舉個例子當異步程序操作
A、B
需要都完成以後才能進行
C
程序操作,在開發中經常會這樣,需要等到上個操作完成或者知道上個操作完成才去觸發下個操作,而
JavaScript
又是單線程的,不能采用阻塞的方式去處理,在
Promise
規範出現之前通常都是使用回調的方式實作,這樣很容易造成回調地獄,等待者模式就是在
Promise
規範制定之前一個類似于
Promise
的解決方案,可以算是
Promise
規範的一個參考前身。
實作
var Waiter = function() {
var dfd = []; // 等待對象容器
var doneArr = []; // 成功回調容器
var failArr = []; // 失敗回調容器
//監控對象類
var Promise = function() {
this.resolved = false; // 監控對象是否解決成功狀态
this.rejected = false; // 監控對象是否解決失敗狀态
}
Promise.prototype = {
//解決成功
resolve: function() {
this.resolved = true; // 設定目前監控狀态是成功
if (!dfd.length) return void 0;
for (var i = dfd.length - 1; i >= 0; i--) {
// 對象監控對象周遊如果任一個對象沒有解決或者失敗就傳回
if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) return void 0;
dfd.splice(i, 1);
}
_exec(doneArr);
},
//解決失敗
reject: function() {
this.rejected = true; // 設定目前監控狀态是失敗
if (!dfd.length) return void 0; // 沒有監控對象取消
dfd.splice(0); // 清除監控對象
_exec(failArr);
}
}
this.Deferred = function() {
return new Promise();
};
//回調執行方法
function _exec(arr) {
for (let i = 0, len = arr.length; i < len; i++) {
try {
arr[i] && arr[i]();
} catch (e) {
// console.warn("Error", e);
_exec(failArr);
}
}
};
// 監控異步方法參數
this.when = function(...args) {
//設定監控對象
dfd = args;
var i = args.length;
//向前周遊監控對象
for (--i; i >= 0; i--) {
//不存在監控對象 監控對象已經解決 監控對象失敗
if (!args[i] || args[i].resolved || args[i].rejected || !args[i] instanceof Promise) {
args.splice(i, 1)
}
}
return this; // 傳回等待者對象
};
//解決成功回調函數添加方法
this.done = function(...args) {
doneArr = doneArr.concat(args); // 向成功毀掉函數容器中添加回調方法
return this;
};
//解決失敗回調函數添加方法
this.fail = function(...args) {
failArr = failArr.concat(args); // 向失敗回調函數中添加方法
return this;
};
}
;(function(){
var waiter = new Waiter(); // 建立一個等待者執行個體
var first = function() {
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 1000);
return promise; // 傳回監聽這對象
}();
var second = function() { // 第二個對象
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 2000);
return promise;
}();
waiter.when(first, second).done(() => {
console.log("success");
}).fail(() => {
console.log("fail");
})
})();
;(function(){
var waiter = new Waiter(); // 建立一個等待者執行個體
var first = function() {
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 1000);
return promise; // 傳回監聽這對象
}();
var second = function() { // 第二個對象
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 3000);
return promise;
}();
waiter.when(first, second).done(() => {
throw new Error("test");
}).fail(() => {
console.log("fail");
})
})();
Promise
Promise
就是異步操作的一個解決方案,用于表示一個異步操作的最終完成或失敗及其結果值,
Promise
有各種開源實作,在
ES6
中被統一規範,由浏覽器直接支援。上面我們實作的等待者模式更類似于
Promise.all()
。
示例
這個方法傳回一個新的
promise
對象,該
promise
對象在
iterable
參數對象裡所有的
promise
對象都成功的時候才會觸發成功,一旦有任何一個
iterable
裡面的
promise
對象失敗則立即觸發該
promise
對象的失敗。這個新的
promise
對象在觸發成功狀态以後,會把一個包含
iterable
裡所有
promise
傳回值的數組作為成功回調的傳回值,順序跟
iterable
的順序保持一緻;如果這個新的
promise
對象觸發了失敗狀态,它會把
iterable
裡第一個觸發失敗的
promise
對象的錯誤資訊作為它的失敗錯誤資訊。
Promise.all
方法常被用于處理多個
promise
對象的狀态集合。
var p1 = new Promise((resolve, reject) => {
resolve("success1");
})
var p2 = new Promise((resolve, reject) => {
resolve("success2");
})
var p3 = new Promise((resolve, reject) => {
reject("fail");
})
Promise.all([p1, p2]).then((result) => {
console.log(result); // 成功狀态 // ["success1", "success2"]
}).catch((error) => {
console.log(error);
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result);
}).catch((error) => {
console.log(error); // 失敗狀态 // fail
})
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://juejin.cn/post/6844903645855612942
https://segmentfault.com/a/1190000021413444
https://www.cnblogs.com/hsp-blog/p/5889842.html