歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~javascript
本文由 前端林子發表於 雲+社區專欄
Promise是CommonJS提出的一種規範,在ES6中已經原生支持Promise對象,非ES6環境能夠用Bluebird等庫來支持。css
在js中任務的執行模型有兩種:同步模式和異步模式。html
同步模式:後一個任務B等待前一個任務A結束後,再執行。任務的執行順序和任務的排序順序是一致的。前端
異步模式:每個任務有一個或多個回調函數,前一個任務A結束後,不是執行後一個任務B,而是執行任務A的回調函數。然後一個任務B是不等任務A結束就執行。任務的執行順序,與任務的排序順序不一致。java
異步模式編程有四種方法:回調函數(最基本的方法,把B寫成A的回調函數)、事件監聽(爲A綁定事件,當A發生某個事件,就執行B)、發佈/訂閱,以及本文要介紹的Promise對象。ajax
Promise是一個用於處理異步操做的對象,能夠將回調函數寫成鏈式調用的寫法,讓代碼更優雅、流程更加清晰,讓咱們能夠更合理、更規範地進行異步處理操做。它的思想是,每個異步任務返回一個Promise對象,該對象有一個then方法,容許指定回調函數。編程
Pending:進行中,剛建立一個Promise實例時,表示初始狀態;數組
resolved(fulfilled):resolve方法調用的時候,表示操做成功,已經完成;promise
Rejected:reject方法調用的時候,表示操做失敗;瀏覽器
這三種狀態只能從pendeng-->resolved(fulfilled),或者pending-->rejected,不能逆向轉換,也不能在resolved(fulfilled)和rejected之間轉換。而且一旦狀態改變,就不會再改變,會一直保持這個結果。
彙總上述,建立一個Promise的實例是這樣的:
//建立promise的實例 let promise = new Promise((resolve,reject)=>{ //剛建立實例時的狀態:pending if('異步操做成功'){ //調用resolve方法,狀態從pending變爲fulfilled resolve(); }else{ //調用reject方法,狀態從pending變爲rejected reject(); } });
用於綁定處理操做後的處理程序,分別指定fulfilled狀態和rejected狀態的回調函數,即它的參數是兩個函數,第一個用於處理操做成功後的業務,第二個用於處理操做失敗後的業務。
//then() promise.then((res)=> { //處理操做成功後的業務(即Promise對象的狀態變爲fullfilled時調用) },(error)=> { //處理操做失敗後的業務(即Promise對象的狀態變爲rejected時調用) });
用於處理操做異常的程序,catch()只接受一個參數
//catch() promise.catch((error)=> { //處理操做失敗後的業務 });
通常來講,建議不要在then()裏面定義rejected狀態的回調函數,而是將then()用於處理操做成功,將catch()用於處理操做異常。由於這樣作能夠捕獲then()執行中的錯誤,也更接近同步中try/catch的寫法:
//try-catch // bad promise.then((res)=> { //處理操做成功後的業務 }, (error)=> { //處理操做失敗後的業務 }); // good promise .then((res)=> { //處理操做成功後的業務 }) .catch((error)=> { //處理操做失敗後的業務 });
接受一個數組做爲參數,數組的元素是Promise實例對象。只有當參數中的實例對象的狀態都爲fulfilled時,Promise.all( )纔會有返回。
實例代碼(可直接在瀏覽器中打開):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise實例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { //建立實例promise1 let promise1 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操做成功'); console.log('1') }, 3000); }); //建立實例promise1 let promise2 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操做成功'); console.log('2') }, 1000); }); Promise.all([promise1, promise2]).then((result) => { console.log(result); }); } </script> </head> <body> <div></div> </body> </html>
結果(注意看時間):
Promise.all()
代碼說明:
1s後,promise2進入fulfilled狀態,間隔2s,也就是3s後,promise1也進入fulfilled狀態。這時,因爲兩個實例都進入了fulfilled狀態,因此Promise.all()才進入了then方法。
使用場景:執行某個操做須要依賴多個接口請求回的數據,且這些接口之間不存在互相依賴的關係。這時使用Promise.all(),等到全部接口都請求成功了,它纔會進行操做。
和all()的參數同樣,參數中的promise實例,只要有一個狀態發生變化(無論是成功fulfilled仍是異常rejected),它就會有返回,其餘實例中再發生變化,它也無論了。
實例代碼(可直接在瀏覽器中打開):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise實例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { //建立實例promise1 let promise1 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操做成功'); console.log('1') }, 3000); }); //建立實例promise1 let promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise1操做失敗'); console.log('2') }, 1000); }); Promise.race([promise1, promise2]) .then((result) => { console.log(result); }) .catch((error) => { console.log(error); }) } </script> </head> <body> <div></div> </body> </html>
結果(注意看時間):
Promise.race()
代碼說明:
1s後,promise2進入rejected狀態,因爲一個實例的狀態發生了變化,因此Promise.race()就馬上執行了。
平時開發中可能常常會遇到的問題是,要用ajax進行屢次請求。例如如今有三個請求,請求A、請求B、請求C。請求C要將請求B的請求回來的數據作爲參數,請求B要將請求A的請求回來的數據作爲參數。
按照這個思路,咱們可能會直接寫出這樣的層層嵌套的代碼:
//------請求A 開始--------- $.ajax({ success:function(res1){ //------請求B 開始---- $.ajax({ success:function(res2){ //----請求C 開始--- $.ajax({ success:function(res3){ } }); //---請求C 結束--- } }); //------請求B 結束----- } }); //------請求A 結束---------
在請求A的success後,請求B發送請求,在請求B 的success後,請求C發送請求。請求C結束後,再向上到請求B結束,請求B結束後,再向上到請求A結束。
這樣雖然能夠完成任務,可是代碼層層嵌套,代碼可讀性差,也不便於調試和後續的代碼維護。而若是用Promise,你能夠這樣寫(示意代碼,無ajax請求):
此處附上完整可執行代碼,可在瀏覽器的控制檯中查看執行結果:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise實例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { let promise = new Promise((resolve, reject) => { if (true) { //調用操做成功方法 resolve('操做成功'); } else { //調用操做異常方法 reject('操做異常'); } }); //then處理操做成功,catch處理操做異常 promise.then(requestA) .then(requestB) .then(requestC) .catch(requestError); function requestA() { console.log('請求A成功'); return '下一個是請求B'; } function requestB(res) { console.log('上一步的結果:' + res); console.log('請求B成功'); return '下一個是請求C'; } function requestC(res) { console.log('上一步的結果:' + res); console.log('請求C成功'); } function requestError() { console.log('請求失敗'); } } </script> </head> <body> <div></div> </body> </html>
結果以下:
實例
能夠看出請求C依賴請求B的結果,請求B依賴請求A的結果,在請求A中是使用了return將須要的數據返回,傳遞給下一個then()中的請求B,實現了參數的傳遞。同理,請求B中也是用了return,將參數傳遞給了請求C。
本文主要介紹了Promise對象的三個狀態和兩個過程。「三個狀態」是:初始化、操做成功、操做異常,「兩個過程」是初始化狀態到操做成功狀態,和初始化狀態到操做異常狀態。除此以前,還有兩種實例方法:then()、catch()來綁定處理程序。類方法:Promise.all()、Promise.race()。若有問題,歡迎指正。
相關閱讀
【每日課程推薦】機器學習實戰!快速入門在線廣告業務及CTR相應知識
此文已由做者受權騰訊雲+社區發佈,更多原文請點擊
搜索關注公衆號「雲加社區」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社區!