前言: 目前前端主要都是透過 AJAX
方法來非同步取得遠端資料,像是 jQuery、Fetch 都是基於 AJAX 概念下,所開發的 API
。而我們今天要介紹的 Promise 有下面幾點特色。
解決了過往不同寫法的差異(如:$.ajax
)
解決了過於巢狀的寫法。使整體結構更優於管理。
參考資料:Day23-非同步實作篇 II!Promise JavaScript Promise 全介紹 Promise MDN
歷史 開始前,我想先介紹一下在還沒有 $.ajax
這個 API
出現前,網頁該如何遠端取得資料呢? 我們這時候就必須透過建立 XMLHttpRequest
物件,來進行資料取得。方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var http = new XMLHttpRequest();http.open("get" ,'https://randomuser.me/api/' ,true ); http.onreadystatechange = function ( ) { if (this .status === 200 ){ console .log("成功" ) } }; http.send();
寫完,我們可以發現,這樣的寫法在管理上其實非常不方便,也會讓程式碼不易閱讀。進而有了 $.ajax
這個 API 產生。
但是我們在使用過後,其實發現 jQuery
方法雖然解決上述問題,但對於過於巢狀根同步處理所有非同步行為上還是有一定難度。
進而有了 Promise 物件的產生,讓我們可以更方便實作 AJAX
。
簡介 Promise 本身是用來改善 JavaScript 非同步的語法結構。而Async、Await
則是基於Promise語法讓非同步的語法的結構類似於 同步語言
,更易讀且好管理。
結構 Promise 本身是一個建構函式,我們可以透過console.log
看到下列四種方式
1 2 3 4 Promise .all() Promise .race() Promise .resolve()Promise .reject()
Promise 建構函式 new 出的物件,則可以使用其中的原型方法(在 prototype 內),其中就包含 then、catch、finally,這些方法則必須在新產生的物件下才能呼叫。
1 2 3 4 let AJAJ = new Promise ( () => { });AJAJ.then(); AJAJ.catch(); AJAJ.finally();
此外,建立新的建構函式時,必須傳入一個函式作為參數(executor function)
,此函式的參數包含 resolve, reject
,這兩個方法分別代表成功與失敗的回傳結果,特別注意這兩個僅能回傳其中之一,回傳後表示此 Promise 事件結束。
1 2 3 4 let AJAJ = new Promise ( function (resolve,reject ) { resolve(); reject(); });
狀態
Pending -> 尚未得到結果
Resolved:事件已經執行完畢且成功操作,回傳 resolve
的結果
Rejected:事件已經執行完畢但操作失敗,回傳 rejected
的結果
圖片來源:卡斯伯文章
接著,不論成功或失敗我們可以透過then
、catch
、finally
來取得結果。
補充一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 在 .then(onFulfilled, onRejected)中可帶入兩個回呼函式 ,只是實務上我們很少這樣做就是 onFulfilled:執行成功的函式,所帶入參數表示 Promise 函式中 resolve 所帶入的值。 onRejected:執行失敗的函式,帶入參數表示 Promise 函式中 reject 所帶入的值。 promise().then((success ) => { console .log('success' ) }, (fail ) => { console .log('fail' ) }) promise() .then(success => { console .log('success' ) }) .catch(fail => { console .log('fail' ) }) .finally(last => { console .log('最終結果' ) })
實作 要將一個觀念熟記,自己動手寫一遍是最恰當的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 let Promise = new Promise (); let newPromise = new Promise ((resolve, reject ) => { resolve("success" ); }); newPromise .then((res ) => { console .log(1 , res); }).catch(error => { console .log(error); }); console .dir(newPromise);function chainPromise (num ) { return new Promise ((resolve, reject ) => { setTimeout (() => { if (num) { resolve(`${num} success` ); } else { reject(`${num} fail` ); } }, 10 ); }); } chainPromise(0 ) .then((res => { console .log(res); }),(reject => { console .log(reject); })); chainPromise(0 ) .then(res => { console .log(res); }) .catch(error => { console .log(error); })