在過去 JS 要處理 Ajax 這個非同步語法,會很容易用到 Callback 寫法,而 Callback 不但不好管理,還容易寫成 Callback Hell,如圖:
幸好 ES6 新增了 Promise ,對於 JS 這個單執行序的語言 Promise 非常實用。
Promise 直接翻譯成中文會是承諾 ,而 Promise 的使用結果也就分成兩種
resolve()
reject()
而要使用 Promise
大致上分為兩個步驟:
new Promise()
的函式建構式創造一個新的 Promise 物件Promise
物件在創造函式建構式時,函式建構式會帶上兩個參數 resolve
、 reject
, 第一個參數是用來執行 成功的方法,第二個則是 失敗的方法,這兩個參數名稱接可以自定義,不過實際開發時多數,仍會使用這個名稱做命名。
(這邊是把 Promise 寫成函式方法,因此可以帶入參數,在透過參數來做判斷。)
function PromiseFn(String) {
// 創造建構函式並帶上 resolve 、 reject 參數
return new Promise((resolve, reject) => {
setTimeout(function () {
// Promise 承諾的判斷
if (String.length >= 5) {
resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
建立好 Promise
函式建構式後,便是執行 Promise
本身了,接者執行 Promise
本身時,我們可以使用 then()
、 catch()
他們會分別接收 Promise
成功 以及 Promise
失敗的結果,但他們需要寫上一個 Callback Function ,若要顯示 Promise 建構式中的 resolve()
、 reject()
設定的資料,那麼會需要在 Callback Function 中帶上一個參數,這些參數就會顯示 resolve()
、 reject()
設定的資料:
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
PromiseFn('test')// Promise 失敗
.then((res)=>{ // 第一個參數會回傳 resolve() 設定資料
console.log(res)
})
.catch((err)=>{
console.log(err) // 第一個參數會回傳 reject() 設定資料
})
PromiseFn('Ryder') //Promise 成功, Ryder 共 5 個字
.then((res)=>{
console.log(res)
})
.catch((err)=>{
console.log(err)
})
扣除上面的 Promise 基本方法,Promise 還提供 Promise.all()
、 Promise.race()
兩種用法。
Promise.all()
時,會執行 Promise.all()
中所有的 Promise 方法,並將回傳一個陣列,而這個陣列就是 resolve()
所提供的。function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${ String } 共 ${ String.length } 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
Promise.all([PromiseFn('Ryder'), PromiseFn('youtube')]).then((res)=>{
console.log(res) //['Promise 成功, Ryder 共 5 個字 ', 'Promise 成功, youtube 共 7 個字 ']
})
Promise.race()
和 Promise.all()
一樣,會同時執行 Promise.race()
中所有 Promise 方法,但他只會回傳最快執行完畢的 Promise 方法。const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
Promise.race([PromiseFn('Ryder'), p]).then((res) => {
console.log(res) //直接執行 Promise
})
上面介紹的 Promise.all()
Promise.race()
都是會同時執行的方法,不過我們肯定會遇到需要依序執行 Promise
的狀況,在過去使用 Callback Function 時就會寫出超巢的 Callback Hell,不過 Promise
則提供了鏈式寫法,可以輕鬆的達成需求。
要使用 Promise
的鏈式寫法,只需要在 then()
中使用 return
並呼叫下一個 Promise
這樣變能使用 .then()
不斷串聯下去。
const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
PromiseFn('Ryder')
.then((res) => {
console.log(res) // Promise 成功, Ryder 共 5 個字
return PromiseFn('youtube') // Promise 鏈式寫法,可以不斷寫 Promise 下去。
}).then((res) => {
console.log(res) // Promise 成功, youtube 共 7 個字
return p
}).then((res) => {
console.log(res) // 直接執行 Promise
})