promise
是 ES6 新增的語法,主要用來處理非同步行為,promise
也可以直接用中文理解:這個承諾可以被兌現或是拒絕,也就對應到了 resolve
(成功) 以及 reject
(失敗)。
透過建構函式 new
一波,一旦建立後就有相關的方法可以呼叫(then、catch 等)。
const promise = new Promise((resolve, reject) => {
resolve("success");
reject("error");
});
而 Promise
內必須傳入一個函式,這個函式會接收兩個參數,分別是 resolve
& reject
(選填),成功及失敗時會被調用,一旦調用後 promise
的狀態就會被改變,同時只能調用其中一種。
上面提到調用後狀態就會被改變,狀態可以分為以下:
pending
承諾尚未兌現 (PromiseState:Pending)resolved
承諾已履行 (PromiseState:Fulfilled)rejected
拒絕承諾 (PromiseState:Rejected)要注意的是,一旦狀態被改變後就不會再更動了。我們可以 log 出 PromiseState
來看看現在的狀態:
const promise = new Promise((resolve, reject) => {
// ...
});
console.log(promise)
一般在使用 promise
會用 then
和 catch
代表成功及失敗要做的事情:
promise.then(); // Promise 回傳正確
promise.catch(); // Promise 回傳失敗
promise.finally(); // 非同步執行完畢(無論是否正確完成)
在 then
中使用 return 回傳另一個 promise
,就是 Promise 鏈的用法,再下一個 then
中會繼續執行,就不會有 callback hell
的情況發生。
promise
.then((res) => {
console.log(res)
return promise; // 回傳 promise
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
但如果第二個 promise
被拒絕則會接跳到 catch
的地方。
另外 finally()
非同步執行完畢後才會執行,可以用來確認該 promise 是否有執行。
接下來看看 Promise
還有哪些方法可以使用:
當我們想要一次執行多個 promise
就可以使用 all(),參數中接受陣列,陣列中放多個 promise
。
用法與一般的類似,實際寫會類似這樣:
// n < 3 才會成立
function promise(n) {
return new Promise((resolve, reject) => {
if (n < 3) {
resolve("success");
} else {
reject("error");
}
});
}
// 參數放陣列,這邊都成功所以不會進到 catch
Promise.all([promise(1), promise(2)])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
all()
的注意點:
promise
完成後會回傳一個陣列,陣列裝著各個 promise
的 callback
。rejected
,則回傳第一個 rejected
的 promise
。與上面的 all()
差不多,參數一樣接受陣列,差別在於:
只要任一個 promise
狀態改變,則回傳該個 promise
的 callback
。
Promise.resolve()
函數用來將一個物件轉型為 Promise
(如果它不是一個 Promise 物件),然後立刻 resolve 它。
const promise = Promise.resolve("success");
promise.then((res) => {
console.log(res); // success
});
Promise.reject()
函數用來將一個物件轉型為 Promise
(如果它不是一個 Promise 物件),然後立刻 reject 它。
簡單來說就是跟上面相反
const promise = Promise.reject("error");
promise.catch((err) => {
console.log(err); // error
});
Async Await
是 ES7 新增的語法,也同樣用來處理非同步行為、並且是 Pormise
的語法糖,能讓函式以「同步」的方式來執行程式。
語法上有兩個重點:
function
前面添加 async
關鍵字。try & catch
做例外處理。// 建立一個 promise
const promise = new Promise((resolve, reject) => {
resolve(1)
});
// 立即執行這個 async function
(async function asyncFn(){
try {
const res = await promise;
console.log(res) // 印出 1
}catch(err){
console.log(err)
}
})()
上面的範例中可以看到 await
,這個用法等同於 promise
中使用的 then
。這個 API 與 async 是好朋友,並不會單獨出現,也就是外層如果沒有 async
關鍵字,內部無法使用 await
。
當然 await
沒有規定執行次數:
const promise = (number) => {
return new Promise((resolve, reject) => {
resolve(number)
})
}
(async function asyncFn(){
try {
const res = await promise(1);
const res2 = await promise(2);
}catch(err){
console.log(err)
}
})()
Promise
中使用 catch
來捕捉錯誤,在 async function 如果沒有特別針對錯誤做處理的話,一旦發生錯誤會導致程式碼無法繼續執行。
// 參數 number 大於 10,進入 reject
const promise = (number) => {
return new Promise((resolve, reject) => {
if(number > 10){
reject("WTF!!!!")
}else{
resolve(number)
}
})
}
(async function asyncFn(){
try {
// 進入 rejected 狀態,前往 catch
const res = await promise(99);
}catch(err){
console.log(err) // 印出 WTF!!!!
}
})()