您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“ES6的Promise怎么用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“ES6的Promise怎么用”這篇文章吧。
Promise 是異步編程的一種解決方案,其實是一個構造函數,自己身上有all、reject、resolve這幾個方法,原型上有then、catch等方法。(ps:什么是原型:http://www.mlszssj.com/article/231967.htm)
Promise對象有以下兩個特點。
(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
下面先 new一個Promise
let p = new Promise(function(resolve, reject){ //做一些異步操作 setTimeout(function(){ console.log('執行完成Promise'); resolve('要返回的數據可以任何數據例如接口返回數據'); }, 2000); });
刷新頁面會發現控制臺直接打出
其執行過程是:執行了一個異步操作,也就是setTimeout,2秒后,輸出“執行完成”,并且調用resolve方法。
注意!我只是new了一個對象,并沒有調用它,我們傳進去的函數就已經執行了,這是需要注意的一個細節。所以我們用Promise的時候一般是包在一個函數中,在需要的時候去運行這個函數,如:
<div onClick={promiseClick}>開始異步請求</div> const promiseClick =()=>{ console.log('點擊方法被調用') let p = new Promise(function(resolve, reject){ //做一些異步操作 setTimeout(function(){ console.log('執行完成Promise'); resolve('要返回的數據可以任何數據例如接口返回數據'); }, 2000); }); return p }
刷新頁面的時候是沒有任何反映的,但是點擊后控制臺打出
當放在函數里面的時候只有調用的時候才會被執行
那么,接下里解決兩個問題:
1、為什么要放在函數里面
2、resolve是個什么鬼
我們包裝好的函數最后,會return出Promise對象,也就是說,執行這個函數我們得到了一個Promise對象。接下來就可以用Promise對象上有then、catch方法了,這就是Promise的強大之處了,看下面的代碼:
promiseClick().then(function(data){ console.log(data); //后面可以用傳過來的數據做些其他操作 //...... });
這樣控制臺輸出
先是方法被調用起床執行了promise,最后執行了promise的then方法,then方法是一個函數接受一個參數是接受resolve返回的數據這事就輸出了‘要返回的數據可以任何數據例如接口返回數據'
這時候你應該有所領悟了,原來then里面的函數就跟我們平時的回調函數一個意思,能夠在promiseClick這個異步任務執行完成之后被執行。這就是Promise的作用了,簡單來講,就是能把原來的回調寫法分離出來,在異步操作執行完后,用鏈式調用的方式執行回調函數。
你可能會覺得在這個和寫一個回調函數沒有什么區別;那么,如果有多層回調該怎么辦?如果callback也是一個異步操作,而且執行完后也需要有相應的回調函數,該怎么辦呢?總不能再定義一個callback2,然后給callback傳進去吧。而Promise的優勢在于,可以在then方法中繼續寫Promise對象并返回,然后繼續調用then來進行回調操作。
所以:精髓在于:Promise只是能夠簡化層層回調的寫法,而實質上,Promise的精髓是“狀態”,用維護狀態、傳遞狀態的方式來使得回調函數能夠及時調用,它比傳遞callback函數要簡單、靈活的多。所以使用Promise的正確場景是這樣的:
promiseClick() .then(function(data){ console.log(data); return runAsync2(); }) .then(function(data){ console.log(data); return runAsync3(); }) .then(function(data){ console.log(data); });
這樣能夠按順序,每隔兩秒輸出每個異步回調中的內容,在runAsync2中傳給resolve的數據,能在接下來的then方法中拿到。
(Ps:此處執行多次是因為研究該用法的時候我在一個react的demo中進行的,該頁面多個元素改變導致頁面多次渲染執行所致,正常頁面只渲染一次的話就所有只會執行一次)
以上是對promise的resolve用法進行了解釋,相當于resolve是對promise成功時候的回調,它把promise的狀態修改為
fullfiled,那么,reject就是失敗的時候的回調,他把promise的狀態修改為rejected,這樣我們在then中就能捕捉到,然后執行“失敗”情況的回調。
function promiseClick(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } promiseClick().then( function(data){ console.log('resolved成功回調'); console.log('成功回調接受的值:',data); }, function(reason){ console.log('rejected失敗回調'); console.log('失敗執行回調拋出失敗原因:',reason); } );
執行結果:
(PS:此處也是執行多次所以輸出多次,執行多次的原因和上次原因一致)
以上代碼:調用promiseClick方法執行,2秒后獲取到一個隨機數,如果小于10,我們算成功,調用resolve修改Promise的狀態為fullfiled。否則我們認為是“失敗”了,調用reject并傳遞一個參數,作為失敗的原因。并將狀態改成rejected
運行promiseClick并且在then中傳了兩個參數,這兩個參數分別是兩個函數,then方法可以接受兩個參數,第一個對應resolve的回調,第二個對應reject的回調。(也就是說then方法中接受兩個回調,一個成功的回調函數,一個失敗的回調函數,并且能在回調函數中拿到成功的數據和失敗的原因),所以我們能夠分別拿到成功和失敗傳過來的數據就有以上的運行結果
與Promise對象方法then方法并行的一個方法就是catch,與try catch類似,catch就是用來捕獲異常的,也就是和then方法中接受的第二參數rejected的回調是一樣的,如下:
function promiseClick(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } promiseClick().then( function(data){ console.log('resolved成功回調'); console.log('成功回調接受的值:',data); } ) .catch(function(reason, data){ console.log('catch到rejected失敗回調'); console.log('catch失敗執行回調拋出失敗原因:',reason); });
執行結果:
效果和寫在then的第二個參數里面一樣。它將大于10的情況下的失敗回調的原因輸出,但是,它還有另外一個作用:在執行resolve的回調(也就是上面then中的第一個參數)時,如果拋出異常了(代碼出錯了),那么并不會報錯卡死js,而是會進到這個catch方法中。如下:
function promiseClick(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } promiseClick().then( function(data){ console.log('resolved成功回調'); console.log('成功回調接受的值:',data); console.log(noData); } ) .catch(function(reason, data){ console.log('catch到rejected失敗回調'); console.log('catch失敗執行回調拋出失敗原因:',reason); });
執行結果:
在resolve的回調中,我們console.log(noData);而noData這個變量是沒有被定義的。如果我們不用Promise,代碼運行到這里就直接在控制臺報錯了,不往下運行了。但是在這里,會得到上圖的結果,也就是說進到catch方法里面去了,而且把錯誤原因傳到了reason參數中。即便是有錯誤的代碼也不會報錯了
與then同級的另一個方法,all方法,該方法提供了并行執行異步操作的能力,并且在所有異步操作執行完后并且執行結果都是成功的時候才執行回調。
將上述方法復制兩份并重命名promiseClick3(), promiseClick2(), promiseClick1(),如下
function promiseClick1(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } function promiseClick2(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } function promiseClick3(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('數字太于10了即將執行失敗回調'); } }, 2000); }) return p } Promise .all([promiseClick3(), promiseClick2(), promiseClick1()]) .then(function(results){ console.log(results); });
Promise.all來執行,all接收一個數組參數,這組參數為需要執行異步操作的所有方法,里面的值最終都算返回Promise對象。這樣,三個異步操作的并行執行的,等到它們都執行完后才會進到then里面。那么,三個異步操作返回的數據哪里去了呢?都在then里面,all會把所有異步操作的結果放進一個數組中傳給then,然后再執行then方法的成功回調將結果接收,結果如下:(分別執行得到結果,all統一執行完三個函數并將值存在一個數組里面返回給then進行回調輸出):
這樣以后就可以用all并行執行多個異步操作,并且在一個回調中處理所有的返回數據,比如你需要提前準備好所有數據才渲染頁面的時候就可以使用all,執行多個異步操作將所有的數據處理好,再去渲染
all是等所有的異步操作都執行完了再執行then方法,那么race方法就是相反的,誰先執行完成就先執行回調。先執行完的不管是進行了race的成功回調還是失敗回調,其余的將不會再進入race的任何回調
我們將上面的方法延遲分別改成234秒
function promiseClick1(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('2s隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('2s數字太于10了即將執行失敗回調'); } }, 2000); }) return p } function promiseClick2(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('3s隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('3s數字太于10了即將執行失敗回調'); } }, 3000); }) return p } function promiseClick3(){ let p = new Promise(function(resolve, reject){ setTimeout(function(){ var num = Math.ceil(Math.random()*20); //生成1-10的隨機數 console.log('4s隨機數生成的值:',num) if(num<=10){ resolve(num); } else{ reject('4s數字太于10了即將執行失敗回調'); } }, 4000); }) return p } Promise .race([promiseClick3(), promiseClick2(), promiseClick1()]) .then(function(results){ console.log('成功',results); },function(reason){ console.log('失敗',reason); });
當2s后promiseClick1執行完成后就已經進入到了then里面回調,在then里面的回調開始執行時,promiseClick2()和promiseClick3()并沒有停止,仍舊再執行。于是再過3秒后,輸出了他們各自的值,但是將不會再進入race的任何回調。如圖2s生成10進入race的成功回調后,其余函數繼續執行,但是將不會再進入race的任何回調,2s生成16進入了race的失敗回調,其余的繼續執行,但是將不會再進入race的任何回調。
race的使用比如可以使用在一個請求在10s內請求成功的話就走then方法,如果10s內沒有請求成功的話進入reject回調執行另一個操作。
補充:(由于有人問我怎么實現race的使用比如可以使用在一個請求在10s內請求成功的話就走then方法,如果10s內沒有請求成功的話進入reject回調執行另一個操作。這個問題,想是我的表達有點問題,那我就舉個例子)
//請求某個table數據 function requestTableList(){ var p = new Promise((resolve, reject) => { //去后臺請求數據,這里可以是ajax,可以是axios,可以是fetch resolve(res); }); return p; } //延時函數,用于給請求計時 10s function timeout(){ var p = new Promise((resolve, reject) => { setTimeout(() => { reject('請求超時'); }, 10000); }); return p; } Promise.race([requestTableList(), timeout()]).then((data) =>{ //進行成功回調處理 console.log(data); }).catch((err) => { // 失敗回調處理 console.log(err); });
請求一個接口數據,10s內請求完成就展示數據,10s內沒有請求完成就提示請求失敗
這里定義了兩個promise,一個去請求數據,一個記時10s,把兩個promise丟進race里面賽跑去,如果請求數據先跑完就直接進入.then成功回調,將請求回來的數據進行展示;如果計時先跑完,也就是10s了數據請求還沒有成功,就先進入race的失敗回調,就提示用戶數據請求失敗進入.catch回調,(ps:或者進入reject的失敗回調,當.then里面沒有寫reject回調的時候失敗回調會直接進入.catch)
以上是“ES6的Promise怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。