衆所周知,Promise是爲了解決回調地獄問題而產生的,其主要應用於向發服務端發起請求等異步操。那麼,除了異步請求還有其餘場景適合使用 Promise 嗎?下面咱們來共同探討下。javascript
Promise除了用於異步操做,還能夠用來記錄一個業務流程的狀態變化,俗稱「狀態機」。咱們可使用 Promise 提供的 Promise.all
方法來實現並行執行任務。好比如今有一個表單頁,裏面有若干多個表單項,只有在全部表單都經過校驗才容許用戶進行下一步操做。下面咱們來提煉關鍵要素:java
當看到這樣的業務邏輯時,是否是首先想到的是設置一個 flag
變量,而後經過改變flag
變量來表示全部表單是否校驗經過,這是最容易想到的實現思路。promise
let flag = true;
let fields = [];
fields.forEach(field=>{
if(!field.validate()) {
flag = false;//校驗不經過
}
})
複製代碼
咱們如今來考慮下這麼作有沒有問題?咱們保存了多餘的變量,而且這樣的代碼是不支持遠程服務端校驗的,若是要支持異步操做須要增長更多的代碼量,並且這樣的代碼也是難以理解和維護的。這個時候咱們不妨轉換下思路,將每一個表單項校驗看作是一個 Promise 狀態機,當校驗經過, Promise
狀態爲 fullfilled
,校驗不經過爲 rejected
。如今咱們使用 Promise 重構上面的代碼,使每個表單校驗都支持異步操做,而且更加容易理解。併發
咱們能夠利用
Promise.all
的特性,只有在全部表單項狀態都爲fullfilled狀況下,才容許執行Promise.all後面的then方法app
let p1 = new Promise(function(resolve,rejected) {
//表單1校驗經過
if(field.validate()) {
resolve()
} else {
rejected()
}
})
//p2,p3...
Promise.all([p1,p2,p3...]).then(()=>{
//全部表單項都校驗經過
})
複製代碼
有時候咱們會遇到有一系列任務順序執行的狀況。舉個例子,如今有一個購物車的需求,用戶必須先下單以後才能進行付款,而後付款以後才能夠跳轉到訂單頁面,這個需求就能夠用 Promise 順序執行的邏輯實現,狀態流轉是這樣的:異步
實現這樣的業務邏輯咱們一樣能夠不使用 Promise,可是可能實現過程較複雜。咱們知道,系統越是複雜,出錯的機率越高,因此咱們必須用盡可能簡單的方法實現以上需求。這裏咱們將用到 Promise 的順序執行。
實現Promise順序執行需求如下兩個步驟:async
then()
得到新的 promise,更新promise 變量//利用forEach實現
function run(tasks=[]) {
let promise = Promise.resolve();
tasks.forEach(task=>{
promise = promise.then((value)=>{
return task(value);
})
})
return promise;
}
複製代碼
//利於reduce實現
function run(tasks=[]) {
let promise = tasks.reduce((prev,task)=>{
return prev.then((value)=>{
return task(value);
})
},Promise.resolve());
return promise
}
複製代碼
固然,Promise並非萬金油,不是全部的場合都適合用 Promise。若是是較爲簡單的邏輯,使用 callback 會更加方便。並且若是咱們是在寫一個不少人都在用的公共庫的話,有些開發者可能不喜歡使用Promise或者對 Promise 不熟悉。這時,咱們須要提供一種解決方案,使咱們的API能夠同時兼容 Promise 和 callback 兩種模式。提供一個回調API,回調參數可選,通常狀況下使用 callback,在 callback 未傳遞的狀況下使用 Promise。咱們能夠經過高階函數實現此功能:函數
//將返回promise的函數轉化爲既返回promise又支持
//callback的函數,調用時最後一個參數爲callback
function ptc (fn) {
if(typeof fn !== 'function') {
throw new Error("缺乏必要參數");
}
return function(...args) {
let callback = args[args.length-1];
let _args = args.slice(0,args.length-1);
return fn.apply(this,args).then(res=>{
if(typeof callback == 'function') {
callback.call(this,null,res)
}
return res;
}).catch(e=>{
if(typeof callback == 'function') {
callback.call(this,e,null)
}
return e;
})
}
}
//測試
a= function(x) {return Promise.resolve(x)}
b=pc(a)
b('xxx',function(err,data){
console.log(err,data)//err:null,data:'xxx'
})
b('asss').then(res=>{
console.log(res);
})
複製代碼
Promise 實例能夠看作是一個狀態機,任何具備狀態和狀態改變的業務流程均可以使用 Promise 來實現,在結合了 ES7 的 async function
特性後功能更增強大。這裏咱們只是列舉了兩個很簡單的小例子來幫助你們理解,更多複雜的應用場景等待你們去細心觀察和總結,共勉!測試