鐵人賽
React
javascript
nodejs
鐵人賽第22天,今天我們要談談JS
的Promise
。開發前端不免要對後台要資料,Promise
的觀念能幫助我們理解。
Promise
來確認彼此的關係。女友說~「鼻鼻~今晚八點吃飯,餐廳等,別忘囉~!」
面對喜歡的女生,你信誓旦旦給了一個承諾~「當然~因為妳值得~」
承諾之後,腦子會自動模擬兩種狀況...
(1) 準時赴約 => 感情加溫 (resolve,承諾達成)
(2) 干~忘了 => 女友爆炸了 (reject, 拒絕履行承諾)//<-- 母湯~很危險
setTimeout
就是一個異步設計
- 老闆說, 十分鐘之後回我電話,你答應後,不會傻傻的等,你會滑滑手機,關心一下喜歡的女生~
安安~你好~睡了沒~?
- 時間到了,電話撥出
簡單來說,異步程式其實說穿了,就是平行設計的概念,主執行緒在運作的同時,另一個任務也同時被完成。
JS
雖然是單執行緒,不過,透過運行於Node
或瀏覽器
提供的API協助,這些異步程式可以在背景輕鬆完成!
Promise
就是提供我們異步設計,例如,前端的網頁需要先確認後台的連線是否正常,你會有以下的設計:
(1). 啟動異步:檢察網路連線
(2). 等待網頁的同時,先處理其他的畫面,或顯示loading...
(3). (1)回覆連線狀態,成功! 開始顯示完整網頁
失敗! 出現GG的畫面
我們改寫上張圖來說明
Promise
函式有兩個輸入的函式變數
:resolve及reject
,在這裡,你可以做些事情,並判斷事情的結果符不符合你的預期。
- 如果你的程式「符合」你的預期,你可以用
resolve
去觸發resolved事件
- 如果你的程式「不符合」你的預期,你可以用
reject
去觸發resjected事件
then
是promise
裡的一個函式,同樣吃兩個函式變數
,負責處理resolve
或reject
事件。.js
的視窗下,練習程式碼checkBackend
函式,我們先假設都會回傳true
。true
,我們用resolve
函式來做個回應,此時Promise
的狀態從pending
-> resolved
。
- => 程式的第10行,用(*)做記號
Promise
變數,透過then
觸發了resolve事件
,進而處理。
- => 程式的第16行開始,用(*)做記號
function checkBackend(){
// do something to check
return true; //<-- 感謝Dennis Zheng提醒, false修正為true
}
let p = new Promise((resolve, reject)=>{
let status = checkBackend() //<-- 回傳值
if(status)
resolve("Backend is ready!!") //true, 執行resolve(*)
else
reject("oops...something's wrong~~>_<"); //false, 執行reject
})
p.then(resolveMsg=>{ // 處理resolve事件(*)
console.log(resolveMsg);
},
rejectMsg=>{// 處理reject事件
console.log(rejectMsg)
})
//=== 終端機會印出如下訊息 ===
//Promise { <pending> }
//> Backend is ready!!
checkBackend()
的回傳值改為false
看看function checkBackend(){
// do something to check
return false;
}
...
p.then(resolveMsg=>{ // 處理resolve事件
console.log(resolveMsg);
},
rejectMsg=>{// 處理reject事件 (*)<--換reject觸發
console.log(rejectMsg)
})
//=== 終端機會印出如下訊息 ===
//Promise { <pending> }
//> oops...something's wrong~~>_<
...
Promise
裡的func
依序呼叫resolve
及reject
,resolve
,所以在第6行會印出okla
let p = new Promise((resolve, reject)=>{
resolve("okla"); //<--只有第一個會被觸發,
reject("oops"); //<--空炮彈,Promise不會處理
})
// 感謝Dennis Zheng提醒, console.log(resolve) 修正為 console.log(resolveMsg)
p.then((resolveMsg)=>console.log(resolveMsg), (rejectMsg)=>console.log(rejectMsg)) //okla
如果你想讓程式碼更乾淨一點,另一種可以更優雅的寫法,使用catch
來處理reject
我們改寫一下上面的範例
p.then(
resolveMsg=>{ // 處理resolve事件
console.log(resolveMsg);
}).catch(
rejectMsg=>{// 處理reject事件 (*)<--換reject觸發
console.log(rejectMsg)
})
承諾的事,總有個結局。finally
,就是我們最後要處理的部分,你可以在這個在finally
進行最後的步驟,例如:提醒主程式狀態為done
,清理記憶體...等
注意finally
雖然吃一個函式,但要注意,函式沒有任何的變數進來喔!
一樣,我們來改寫上面的例子
p.then(
resolveMsg=>{ // 處理resolve事件
console.log(resolveMsg);
})
.catch(
rejectMsg=>{// 處理reject事件 (*)<--換reject觸發
console.log(rejectMsg)
})
.finally(()=>{
// 清理記憶體 或者 通知系統你已經完成任務了
console.log("Done");
})
finally
在最後被執行了!setTimeout
及setInterval
來當作我們驗證的程式let p = new Promise((resolve, reject)=>{ //<--(*) Promise宣告後即正式啟動
let counter = 0;
let timer = setInterval(()=>console.log(counter++), 1000); // 每一秒counter+1, 並印出
setTimeout(
()=>{
clearInterval(timer);
resolve("OKLA");
}, 5000); // 5秒的時候,發出OKLA
})
p.then(
(resolve)=>console.log("done~"+resolve)
)
Promise
一宣告完之後,就馬上啟動了,也就是程式碼第一行的位置(*)
Promise
的完整架構。Promise
的人可能需要點時間消化,慢慢練習,會駕輕就熟的!(2) 干~忘了 => 女友爆炸了 (reject, 拒絕履行承諾)//<-- 母湯~很危險
真的Hen危險哈哈
大大妳兩個範例都是return false喔 console.log的部分寫錯了
感謝Dennis Zheng大大的提醒,已更正兩個錯誤的地方,並在程式碼的地方,標示大大的名稱,以示感謝!
大大不用這樣啦
因為有你的文章才讓我學到相關知識 我該感謝你才對!