JavaScript Promise
ES6 後 JavaScript 開始支援 promise,在沒有 promise 的年代,多個串連的非同步事件處理時常會陷入 callback hell,如 ajax 發送與取得資料。
Callback Hell (Source: The 80/20 Guide to Promises in Node.js)
promise 能以比較簡潔的方式撰寫非同步的處理流程,在以前會使用 callback 的方式處理:
function successCallback(result) {
console.log("It succeeded with " + result);
}
function failureCallback(error) {
console.log("It failed with " + error);
}
function doSomething(successCallback, failureCallback) {
// do something
if (success){
successCallback(result);
}else{
failureCallback(error);
}
}
doSomething(successCallback, failureCallback);
但有了 promise 後,則改為回傳一個 Promise,再以 then
設定成功與失敗的處理函式:
function doSomething(){
return new Promise((resolve, reject) => {
// do something
if (success){
resolve(result);
}else{
reject(error);
}
});
}
doSomething().then(successCallback, failureCallback);
另一個常見的需求則是串連多個 Promise:
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
利用 await
與 async
也可以讓非同步流程以同步程式的方式表達
function doSomething(){
return new Promise((resolve, reject) => {
// do something
if (true){
resolve("result1");
}else{
reject("error1");
}
});
}
function doSomethingElse(result){
return new Promise((resolve, reject) => {
// do something
console.log(result)
if (true){
resolve("result2");
}else{
reject("error2");
}
});
}
function doThirdThing(result){
return new Promise((resolve, reject) => {
// do something
console.log(result)
if (true){
resolve("result3");
}else{
reject("error3");
}
});
}
async function foo() {
try {
let result = await doSomething();
let newResult = await doSomethingElse(result);
let finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch(error) {
failureCallback(error);
}
}
foo()
// > "result1"
// > "result2"
// > "Got the final result: result3"
也可以利用 Promise.all
同時執行多個非同步函數,全部成功時回傳 list,或任一個失敗時進入 catch:
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
axios 也是以 Promise 為 base 發送 HTTP Request,例如一個基礎的 get request:
const axios = require('axios');
// Make a request for a user with a given ID
axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
Reference: