Promise學習筆記(一)
前言
一開始學習前端的時候,很多技術都是學習其用法,實際上很少去了解其原理,因此在空閒時,去寫一些筆記記錄一下自己對一些常用技術的原理理解。
什麼是Promise?
Promise 是ES6提供的一個物件,Promise物件代表了未來將要發生的事件,用來傳遞非同步操作的訊息;常用在網路請求中。
Promise物件的狀態不受外界影響,它有三種狀態
·pending 進行中
·fulfilled 已成功
·rejected 已失敗
Promise的狀態只能由非同步操作的結果決定。並且,Promise物件的狀態既定,便不會再發生改變,且任何時候都能夠得到其結果。Promise的狀態改變通常只有 pending——fulfulled || pending——rejected。
Promise的優缺點
Promise物件可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。而且Promise物件提供了統一的介面,使得控制非同步操作更加容易。
但是,Promise一旦新建就會立即執行,中途是無法取消的。其次,若不設定回撥函式,Promise內部丟擲的錯誤,是不會反應到外部(由於它內部不會受到外部的影響)。當Promise物件處於pending狀態時,是無法得知目前進展到哪一個階段。
Promise基礎使用
使用一個東西的時候,我們常常需要了解這個東西內部提供了什麼給我呼叫,所以先看一下Promise。
通過列印可以看出來,Promise是一個建構函式,它本身有all、reject、resolve方法,原型上還有then、catch等方法。所以想要建立一個Promise,使用new關鍵字即可。
let pro = new Promise (function (resolve, reject) { setTimeout (function () { console.log('Promise執行完畢') resolve('返回資料,通知回撥執行') }, 1000) })
Promise的建構函式接收一個函式作為引數,函式傳入了兩個引數,分別為 resoleve 和 reject,前者代表了非同步操作成功(pending—fulfilled)的回撥函式,後者代表了非同步操作失敗(pending—rejected)的回撥函式。
上面的程式碼,執行了一個非同步操作,也就是定時器,在1秒後,輸出“Promise執行完畢”,並且呼叫resolve方法。
實際上,當我們使用new關鍵字建立Promise物件時,被當做引數的函式傳進去的時候已經執行了。所以我們使用Promise的時候,一般當做變數存放在一個函式中,在需要的時候再去執行這個函式。
function go () { let pro = new Promise (function (resolve, reject) { setTimeout (function () { console.log('Promise執行完畢') resolve('返回資料,通知回撥執行') }, 1000) }) return pro }
那再看回來,為什麼我們要把Promise包在函式中,還有就是resolve在這裡面是什麼作用。
上面的截圖中,我們知道了Promise實際上是一個建構函式,可以呼叫then、catch方法。當我們將Promise包在函式中,我們可以這樣使用
function go () { let pro = new Promise (function (resolve, reject) { setTimeout (function () { console.log('Promise執行完畢') resolve('返回資料,通知回撥執行') }, 1000) }) return pro } go().then(function(data){ console.log('在這執行後續的操作,data是resolve傳遞的引數') })
看了上面這段程式碼,就懂了,then裡面的函式實際上差不多是我們平時使用的回撥函式。這個時候,可能會有個疑惑,既然這樣子的用法,跟我們平時呼叫方法再寫回調函式沒什麼區別,為什麼還要大費周折地去用Promise?那再往回調裡去想,如果有多層回撥,而且回撥本身也是一個非同步操作呢?如果按照傳統的寫法來處理,會進入回撥地獄,後期維護成本會很大,維護難度高,而Promise可以在then中繼續寫Promise物件並返回,然後繼續呼叫then來進行回撥操作,可以避免上述問題。
看到這裡,我們似乎忘記了什麼,emmmm..... 就是reject。那我們看一下下面的程式碼,很容易就理解了,這裡使用一段ajax請求來寫。
function ajax(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } var URL = "請求地址"; ajax(URL).then( function success(data){ console.log('resolve') }, function fail(reason, data) { console.log('reject') } )
請求成功時,我們會用resolve傳遞成功的返回值去進行回撥操作,失敗或者出現異常時,則使用reject傳遞引數。在程式碼中,可以看到,then方法中接收了兩個函式作為引數,第一個為resolve的回撥,第二個為reject的回撥。
上述則是個人對於Promise基礎使用的一些心得。