JS-[promises篇]-消耗一個promise以及串接promise 與錯誤處理


這裡要繼續討論的是如何使用或處理 Promise 得到的最終狀態,通常是通過 .then() 方法来獲取 Promise 的值或處理 Promise 的狀態

複習promise

當我們寫下:

會得到什麼?其實這一段就等同於我們在建構promise,也就是說,這段Fetch get請求,建構了promise,不過仍然是一個懸而未決的狀態<pending>

假定中樂透的狀態.then(fn(){... return})

而我要對自己建構的promise/樂透有信心啊!所以起手式都是假定promise的<pending>狀態將會進入“fulfilled/已實現”的狀態,所以我們會用.then()這個語法來處理“fulfilled/已實現”的狀態,也可以想成.then()就是在計畫我中樂透的並收到中獎(資料)的規劃

response在控制台的回傳是這樣:

response.json()

我們透過Fetch API取的的資料會是一個reaponse打包的物件,因此我們可以利用.json()方式將物件轉成可以運用的字串,把response.json()結果輸出來看看

promise return promise 要一層一層剝開..

是的沒有看錯,當我們使用.then()方法時,由裡面的callback fn接收response參數,即使用.json()的方式將response解析,response.json()仍然會回傳一個懸而未決的promise喔!

所以該怎麼做?一樣就是將response.json(),假定為這個promise是一個將來成功得到資料的狀態,所以我們將這個狀態回傳出去,再用一個假定為成功中獎或是得到資料的狀態來接這個promise,也就是另外一個.then()

為什麼在這裡response.json()是一個promise?

由於這點對我來說很重要,因為我會不自覺得繼續寫下去,而不是想到要用另外一個.then()來接

其實是這樣的,fetch()是一個API,它接收到的response是一個 Stream 物件,response.json()是一個非同步操作,取出response所有内容,並將其轉為json格式,這裡有一個重點關鍵字:response.json()是一個非同步操作

  • 我是這樣自我解釋:
    • 我透過fetch API建構promise(仍然是懸而未決的狀態),然後後台繼續執行向遠端非同步請求
    • 而我假定這個會成功,所以用.then()來做成功接收狀態的處理,就接收了從遠端回傳了response物件
    • 然後我在這個.then()中再為這個response使用.json()的做格式轉換的處理,所以在這裡也是非同步行為
    • 因為做格式轉換的動作,他把你這個.json()的請求,丟到後台執行,不知道有沒有解析成功(promise懸而未決的狀態)
    • 所以我也就假定這個.json()會成功,就先return response.json(),用下一個.then()來接收成功的結果(response.json()被解析完的)data,於是就得到了資料

成功回傳


現在來繼續串接promise

把鄰近國家的資料也一併ajax call出來,其實我在callbak hell寫過一次,這裡是用promise的寫法將巢狀的callback hell變成平行時空!

先把上面的promise簡化的優雅一點

加入鄰國的第二個ajax call


這裡邏輯都跟callback hell寫法類似,只是promise的寫法讓我們比較好閱讀跟維護,promise很好的將callback hell 那種程式深深深幾許的巢狀寫法展開來寫,運用.then()方法將ajax calla有序列的實現非同步請求(順序性)這是一大優化!

接下來是繼續介紹promise的錯誤處理,後續還會深入promise語法糖async 與await的寫法


promise的錯誤處理.catch()

使用fetch API最常見的promise進入到rejected的狀態,大部分是使用者電腦離線的狀況居多,連不到API

想要的狀態是,即使在離線狀態,做網路請求時,仍會出現一些錯誤提示,在還沒做任何錯誤處理下,程式碼如下:


上面紅字提示是說,fetch 回傳的promise錯誤狀態,我沒有接住並作出處理
現在要練習的是如何為promise做出rejected的錯誤提示

在.then()的最後面加入 .catch()

.catch((err) => console.log(err))
當任何一個.then方法中出現promise rejected的狀態,都會被移到這個.catch的方法中,裡面會帶一個err參數(錯誤訊息的物件),我試著將它打印出來

自己寫一個錯誤處理的函式


加入在.catch()裡


promise的最後.finally()

.finally()方法是,不論promise的狀態是fulfilled 還是 rejected,在.finally()的程式碼都會在其後被執行,要記得.finally()之所以可以寫在.catch()的後面,原因是,.catch()最後也會返回一個promise

  • 實用性:通常很少使用到,最有可能會用的情況是隱藏“loading spinner",就是不論promise是跑.then()還是.catch()在執行結果顯示畫面之前,可以利用.finally()把loading spinner的狀態隱藏起來,以下用黯淡下去的容器為練習

程式碼修改,把按下按鈕會把國家卡片顯示出來的程式碼挪移到.finally()這行,因為不管是.then()還是.catch()都會有這個動作,就這個動作統一挪至.finally()使用


加入.finally()

正常顯示的情況,會執行最後的.finally()程式碼

錯誤顯示的情況,也會執行最後的.finally()程式碼


補充:手動丟出錯誤 throw Err

promise章節很重要,所以我在這裡的練習費勁了一些心力,好讓自己能理解為什麼,最後來到promise的手動丟出錯誤的補充章節,在上述的練習裡,嘗試來做一個動作會發現一個驚人的事實:

這也是為什麼會有throw new Error()的語法存在
在找不到api的url時,我們試試輸出response物件來看一下

當畫面能正確顯示ok的值會出現這樣

我們可以透過手動創建錯誤的建構子並寫下錯誤的相關訊息與狀態,再用throw關鍵字拋出給.catch()處理

像上面這樣,promise才會立即拋出錯誤處理也就是rejected的狀態

#Promise #return response.json() #.then() #.catch() #throw new Error()







你可能感興趣的文章

Entry-level Software Engineer Quantrix

Entry-level Software Engineer Quantrix

[ 紀錄 ] 實戰練習 - 抽獎程式 (以 Express 實作後端 API )

[ 紀錄 ] 實戰練習 - 抽獎程式 (以 Express 實作後端 API )

Laravel Homestead 設定

Laravel Homestead 設定






留言討論