一,何為Promise?
為了直觀一點(diǎn),首先我們采用console.dir(Promise)看一下它的結(jié)構(gòu)組成。
console.dir(Promise);
從上面的圖片中我們可以到,Promise其實(shí)是一個(gè)構(gòu)造函數(shù)(在JS中,函數(shù)同時(shí)也是一個(gè)對(duì)象),它有resolve,reject,race等靜態(tài)方法;它的原型(prototype)上有then,catch方法,因此只要作為Promise的實(shí)例,都可以共享并調(diào)用Promise.prototype上面的方法(then,catch),接下來我們?cè)囍褂靡幌翽romise。
二,Promise的使用
首先我們來看一下Promise的使用語法:
new Promise(function(resolve,reject){}/*excutor*/);
在實(shí)例化Promise時(shí)需要傳入一個(gè)函數(shù)excutor作為參數(shù),并且在Promise構(gòu)造函數(shù)執(zhí)行時(shí)同步執(zhí)行。廢話不多說,先看一個(gè)簡(jiǎn)單的實(shí)例:
var p = new Promise(function(resolve,reject){ var timer = setTimeout(function(){ console.log('執(zhí)行操作1'); },1000); });
我們可以看到1s后在控制臺(tái)輸出相應(yīng)的結(jié)果,這就說明在實(shí)例化過程中,作為參數(shù)的excutor函數(shù)也會(huì)執(zhí)行。
從上面的實(shí)例中我們看到,excutor函數(shù)還有兩個(gè)參數(shù)resolve和reject,其實(shí)這兩個(gè)參數(shù)也是函數(shù),在excutor執(zhí)行時(shí)被調(diào)用,下面我們具體來談?wù)剅esolve和reject的用法。
三,resolve和reject的具體用法
先來說說resolve的用法
首先我們來看看Promise的幾種狀態(tài):
pending: 初始狀態(tài),成功或失敗狀態(tài)。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。
當(dāng)我們?cè)趀xcutor函數(shù)中調(diào)用resolve方法時(shí),Promise的狀態(tài)就變成fulfilled,即操作成功狀態(tài),還記得上面Promise.prototype上面的then和catch方法嗎?當(dāng)Promise狀態(tài)為fullfilled狀態(tài)時(shí)執(zhí)行then方法里的操作,注意了,then方法里面有兩個(gè)參數(shù)onfulfilled(Promise為fulfilled狀態(tài)時(shí)執(zhí)行) 和onrejected(Promise為rejected狀態(tài)時(shí)執(zhí)行),步驟如下:
1,實(shí)例化Promise(new Promise(function(resolve,reject)))
2,用Promise的實(shí)例調(diào)用then方法
具體來看下面的例子:
var p = new Promise(function (resolve, reject) { var timer = setTimeout(function () { console.log('執(zhí)行操作1'); resolve('這是數(shù)據(jù)1'); }, 1000); }); p.then(function (data) { console.log(data); console.log('這是成功操作'); });
簡(jiǎn)單的理解就是調(diào)用resolve方法,Promise變?yōu)椴僮鞒晒顟B(tài)(fulfilled),執(zhí)行then方法里面onfulfilled里的操作。其實(shí)then里面的函數(shù)就是我們平時(shí)所說的回調(diào)函數(shù),只不過在這里只是把它分離出來而已。我們可以看到控制臺(tái)上的輸出結(jié)果如下所示:
reject的用法
看了上面的實(shí)例,我相信應(yīng)該也很容易理解reject方法了,就是調(diào)用reject方法后,Promise狀態(tài)變?yōu)閞ejected,即操作失敗狀態(tài),此時(shí)執(zhí)行then方法里面onrejected操作,上面我們提到了then方法有兩個(gè)參數(shù),一種是Promise狀態(tài)為fulfilled時(shí)執(zhí)行(onfullfilled),一種是Promise狀態(tài)為rejected時(shí)執(zhí)行(onrejected),其實(shí)就是類似于jquery里的hover方法里面的兩個(gè)參數(shù)一樣,來看看下面的例子:
var p = new Promise(function (resolve, reject) { var flag = false; if(flag){ resolve('這是數(shù)據(jù)2'); }else{ reject('這是數(shù)據(jù)2'); } }); p.then(function(data){//狀態(tài)為fulfilled時(shí)執(zhí)行 console.log(data); console.log('這是成功操作'); },function(reason){ //狀態(tài)為rejected時(shí)執(zhí)行 console.log(reason); console.log('這是失敗的操作'); });
catch方法
我們注意到除了then方法外,Promise原型上還有另外一個(gè)叫catch的方法,那么這個(gè)方法的作用是什么呢?其實(shí)跟then方法中的第二個(gè)參數(shù)一樣,就是在Promise狀態(tài)為rejected時(shí)執(zhí)行,then方法捕捉到Promise的狀態(tài)為rejected,就執(zhí)行catch方法里面的操作,下面用catch方法改寫上面reject用法里面的例子,如下所示:
var p = new Promise(function (resolve, reject) { var flag = false; if(flag){ resolve('這是數(shù)據(jù)2'); }else{ reject('這是數(shù)據(jù)2'); } }); p.then(function(data){ console.log(data); console.log('這是成功操作'); }).catch(function(reason){ console.log(reason); console.log('這是失敗的操作'); });
為什么會(huì)有promise,他的作用是什么?
promise主要是為了解決js中多個(gè)異步回調(diào)難以維護(hù)和控制的問題.
四,為何用Promise
首先我們來看這樣一個(gè)例子,取4個(gè)定時(shí)器,設(shè)置延遲時(shí)間都為1s,然后每隔1s依次在控制臺(tái)輸出‘我’‘愛’‘米’‘飯’的字樣。代碼如下:
setTimeout(function () { console.log('我'); setTimeout(function () { console.log('愛'); setTimeout(function () { console.log('米'); setTimeout(function () { console.log('飯'); }, 1000); }, 1000); }, 1000); }, 1000);
發(fā)現(xiàn)什么問題沒有?是不是有點(diǎn)感覺回調(diào)函數(shù)的嵌套有點(diǎn)多,如果有更多的回調(diào)函數(shù)呢?是不是使代碼的可讀性和可維護(hù)性都大大降低了呢(回調(diào)地獄?),這時(shí)如果我們使用Promise去實(shí)現(xiàn)這個(gè)效果,雖然可能代碼不會(huì)減少,甚至更多,但是卻大大增強(qiáng)了其可讀性和可維護(hù)性。具體看下面例子:
function getStr1() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('我'); }, 1000); }); } function getStr2() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('愛'); }, 1000); }); } function getStr3() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('米'); }, 1000); }); } function getStr4() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('飯'); }, 1000); }); } getStr1().then(function (data) { console.log(data); return getStr2(); }).then(function (data) { console.log(data); return getStr3(); }).then(function (data) { console.log(data); return getStr4(); }).then(function (data) { console.log(data); })
執(zhí)行效果跟上面一樣,在這個(gè)例子中,將得到Promise實(shí)例的過程封裝成一個(gè)函數(shù)(getStr1,getStr2,getStr3,getStr4)并返回一個(gè)Promise實(shí)例,再用實(shí)例去調(diào)用相應(yīng)的then方法,在每個(gè)then方法中通過return得到下一級(jí)的Promise實(shí)例,比如在第一個(gè)Promise實(shí)例(getStr1())then方法中,通過return返回下一個(gè)Promise對(duì)象(getStr2()),然后再去調(diào)用then方法執(zhí)行里面的操作,再返回下一個(gè)Promise對(duì)象(這里是getStr3()),
這樣一級(jí)一級(jí)下去實(shí)現(xiàn)了鏈?zhǔn)秸{(diào)用,雖然代碼量增加了,但比起前面的層層嵌套,顯然這種方式使得代碼更易讀更易維護(hù)。
小例子:
function checkFunc() { let p = new Promise(function (resolve, reject) { // 一些比較耗時(shí)異步操作 if(操作完成標(biāo)識(shí)) { resolve(); } }); p.then(function (data) { layer.confirm('執(zhí)行下一步操作?', { btn: ['確定', '取消'] }, function () { // 確保上面的操作都完成后,才執(zhí)行下面的操作 // 其他操作... }); }); }