[JS] Promise 的使用
const p = new Promise(callback<resolve, reject>)
// .then() 中可以放入兩個 callback,如果需要提早攔截並處理錯誤是可行的
p.then(<resolveHandler>, [<rejectHandler>])
.then(<resolveHandler2>, [<rejectHandler2>])
.catch(<rejectHandler>)
.finally(<finallyHandler>)
Promise.all('<array>')
Promise.race('<array>')
使用範例:
- 示範 Promise 和 Async/Await @ PJCHENder Gist
- Basic Promise @ JSFiddle
- Promise Chain: 在 callback 中回傳另一個 Promise @ JSFiddle
- Use new Promise directly in .then without putting in callback @ JSFiddle
- Error Handling in Promise @ JSFiddle
- Demo how to use Promise.all() 和 Promise.race() @ JSFiddle
範例:
const p = new Promise((resolve, reject) => {
setTimeout(function () {
resolve(3);
}, 1000);
});
/**
* 方法一:在 callback 中 return new Promise
**/
p.then((value) => {
return new Promise((resolve, reject) => {
console.log(value); // 3
setTimeout(function () {
resolve(value * 2);
}, 1000);
});
});
/**
* 方法二:直接代入會 return Promise 的 function
**/
p.then(promiseFn) // 6
.then((value) => {
console.log(value); // 12
})
.catch((err) => {
// catch any error in "then"
console.log(err);
});
function promiseFn(value) {
console.log(value); // 6
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(value * 2);
}, 1000);
});
}
目錄
[TOC]
觀念
- Promise 有三種狀態:
pending
,resolved/fulfilled
,rejected
。 new Promise
內的函式會立即被執行,當resolve
得到內容後,才會執行.then
。
- 在
.then
的resolvedCallback
中,可以得到在new Promise
中 resolve 內所得到的值(value)。 - 如果在
.then
的resolvedCallback
中return
一個值,則這個值會以 Promise 物件的形式傳到下一個.then
。 - 因此在下一個
.then
的resolvedCallback
中,可以取得上一個.then
中 return 的值。 - 但如果我們在
.then
中是 return 另一個new Promise
,則下一個.then
會等到這個 Promise 中的 resolve 得到值後才執行。 - 且在下一個
.then
的resolvedCallback
中,可以得到上一個new Promise
中resolve
的值
基本使用
/**
* Promise 基本使用
* 在 new Promise 內的函式會被馬上執行,
* 當 resolve 得到內容後,才會執行 .then。
**/
const myPromise = new Promise((resolve, reject) => {
console.log('In new Promise, start callback'); // 立即執行
setTimeout(() => {
// 一秒後執行
let response = 10;
resolve(response);
}, 1000);
});
myPromise.then((value) => {
// 在 myPromise 被 resolve 時執行
console.log('The answer is ' + value);
});
myPromise.catch((error) => {
// 在 myPromise 被 reject 時執行
console.log('error', error);
});
Basic Promise @ JSFiddle
Promise 使用 .then 串接
/**
* Promise 使用 .then 串接
* 在 .then 裡面 resole(value) 的 value 一樣是 promise 物件,
* 可以被傳到下一個 .then 中使用。
**/
const myPromise = new Promise((resolve, reject) => {
console.log('In new Promise, start callback'); // 立即執行
setTimeout(() => {
let data = 10;
resolve(data); // 1 秒後執行
}, 1000);
});
// 在 .then 裡面在 return resolve 的 value
// 這個新的 value 會被傳到下一個 promise 的 resolver 內
myPromise
.then((value) => {
console.log('first .then'); // 被 resolve 後執行
return value + 3;
})
.then((value) => {
// 得到上一個 .then return 的值後執行
console.log('second .then');
console.log('The final value is ' + value);
});
我們可以透過 .then()
去 return 另一個 Promise,主要方法有兩種:
- 在 Promise 的
.then
callback 中去new
另一個 Promise - 直接在
.then
中透過 function 的方式new
Promise 而非在 callback 中執行
如果是在 Promise 的
.then
callback 中去new
另一個 Promise,要把這個 Promise 前面加上 return;如果是直接把它放在 .then 的 function 中,則不用在前面加上 return。
方法一:在 .then 的 callback 中 new 另一個 Promise
我們可以在一個 Promise 的 .then 中去 return 另一個 new Promise,:
.then((value) => {
return new Promise((resolve, reject) => {
resolve(value + 3)
})
})
// 這個 .then 會等到上面那個 Promise 被 resolved 後才執行
.then((value)=>{
console.log(value)
})
範例一
/**
* 在 Promise 中 new 另一個 Promise
**/
const myPromise = new Promise((resolve, reject) => {
// 立即執行
console.log('In first Promise, start callback');
setTimeout(() => {
let data = 10;
resolve(data); // 2 秒後執行
console.log('In fist Promise, resolve data');
}, 1500);
});
// 當前面 Promise 的 resolve 得到內容後,才會執行 .then
myPromise
.then((value) => {
// 在.then 的 resolvedCallback 中,可以得到在 new Promise 中 resolve 內所得到的值(value)。
console.log('In first then, the value is ' + value);
// 如果在 .then 的 resolvedCallback 中 return 一個值,則這個值會以 Promise 物件的形式傳到下一個 .then
return value + 3;
})
.then((value) => {
// 因此在這個 .then 的 resolvedCallback 中,可以取得上一個 .then 中 return 的值。
console.log('In second then, the value is ' + value);
console.log('In second Promise, start callback');
// 如果我們在 .then 中是 return 另一個 new Promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// 2 秒後再執行
resolve(value + 3);
console.log('In second Promise, resolve data');
}, 1500);
});
})
// 則下一個 .then 會等到這個 Promise 中的 resolve 得到值後才執行。
.then((value) => {
// 在這個 .then 的 resolvedCallback 中,可以得到上一個 new Promise 中 resolve 的值
console.log('In third then, the value is ' + value);
})
.catch((reason) => {
console.log('Request Failed ' + reason);
});
output 的結果會分成兩個時間點:
--------- 立即執行
"In first Promise, start callback"
--------- 1.5 秒後執行
"In fist Promise, resolve data"
"In first then, the value is 10"
"In second then, the value is 13"
"In second Promise, start callback"
--------- 再 1.5 秒後執行
"In second Promise, resolve data"
"In third then, the value is 16"
範例二
/**
* EXAMPLE2: Return a new Promise in a Promise
**/
function waitASecond(seconds) {
console.log('start', seconds);
return new Promise((resolve, reject) => {
setTimeout(function () {
seconds++;
resolve(seconds);
}, 1000);
});
}
waitASecond(0)
.then((seconds) => {
console.log('In first .then', seconds);
return waitASecond(seconds);
})
.then((seconds) => {
console.log('In second .then', seconds);
return waitASecond(seconds);
})
.then((seconds) => {
console.log('In third .then', seconds);
});
Promise Chain: return a Promise in a Promise @ JSFiddle
方法二:在 .then 中代入會 return Promise 的函式
範例一
// EXAMPLE 1
function waitASecond(second) {
console.log(second);
return new Promise((resolve, reject) => {
setTimeout(function () {
second++;
resolve(second);
}, 1000);
});
}
waitASecond(0)
.then(waitASecond)
.then(waitASecond)
.then((second) => {
console.log(second);
});
範例二
// EXAMPLE2
const calculatePromise = new Promise((resolve, reject) => {
console.log('In new Promise, start callback');
setTimeout(() => {
let answer = 3 + 5;
resolve(answer);
}, 1000);
});
function addTwo(value) {
console.log('current value', value);
return value + 2;
}
function printResult(value) {
console.log('The final value is ' + value);
}
calculatePromise.then(addTwo).then(addTwo).then(printResult);
Use new Promise directly in .then without putting in callback @ JSFiddle
Promise 錯誤處理
可以在 Promise 的任何一個階段中加上 .catch(<err>)
做為錯誤處理,除非有特殊需要,不然 .catch()
通常會放在最後,在任何一個 .then()
的階段中有錯誤發生時,就會直接跳到最後的 .catch()
而不會繼續執行錯誤發生後的 .then()
:
/**
* Error Handling in Promise
**/
function waitASeconds(seconds) {
return new Promise((resolve, reject) => {
if (seconds > 3) {
reject('seconds is bigger then 3');
}
setTimeout(function () {
seconds++;
resolve(seconds);
}, 1000);
});
}
waitASeconds(0)
.then((seconds) => {
console.log('In first .then', seconds);
return waitASeconds(seconds);
})
.then((seconds) => {
console.log('In second .then', seconds);
return waitASeconds(seconds);
})
.then((seconds) => {
console.log('In third .then', seconds);
return waitASeconds(seconds);
})
.then((seconds) => {
console.log('In forth .then', seconds);
return waitASeconds(seconds);
})
.then((seconds) => {
console.log('In fifth .then', seconds);
return waitASeconds(seconds);
})
.catch((error) => {
console.warn(error);
});
Error Handling in Promise @ JSFiddle