0%

JS 核心觀念筆記 - Promise 鏈接方法與常用方法

core

延續上一篇使用的程式碼,並在修改函式的 resolve 的結果,會帶出參數的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function promiseFn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (num) {
resolve(`success ${num}`);
} else {
reject("error");
}
}, 0);
});
}

promiseFn(1)
.then((res) => {
console.log(res);
})
.catch((rej) => {
console.log(rej);
});

Promise Chain

倘若要在原本的 promise 再做一個 promise,就會在第一個 then() 中, return 第二個 promiseFn(params),並且在後面直接再加一個 then() 來接收新的 promiseFn(params) 函式的結果。

1
2
3
4
5
6
7
8
9
10
11
promiseFn(1)
.then((res) => {
console.log(res); // success 1
return promiseFn(2);
})
.then((res) => {
console.log(res); // success 2
})
.catch((rej) => {
console.log(rej);
});

倘若中間有一個參數非真值的話,就會直接跳到 catch()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
promiseFn(1)
.then((res) => {
console.log(res); // success 1
return promiseFn(0);
})
.then((res) => {
console.log(res); // 不會執行,會直接跳到 catch
return promiseFn(3);
})
.then((res) => {
console.log(res);
})
.catch((rej) => {
console.log(rej);
});

如果在 catch() 之後想要再進行新的 promise 是可以的,前面結果失敗後,會重啟一個新的 promise,如下方程式碼,會在失敗後繼續執行 promiseFn(4) 的結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
promiseFn(1)
.then((res) => {
console.log(res); // success 1
return promiseFn(0);
})
.then((res) => {
console.log(res); // 不會執行,會直接跳到 catch
return promiseFn(3);
})
.then((res) => {
console.log(res);
})
.catch((rej) => {
console.log(rej);
return promiseFn(4);
})
.then((res) => {
console.log(res); //success 4
});

CodePen: https://codepen.io/hnzxewqw/pen/ExKBVJr?editors=1111

then() 也可接收錯誤資料

前面提到大部分 then() 是用來接收成功的結果,但其實也可以接收錯誤的結果,程式碼可以這樣寫:

1
2
3
4
5
6
7
8
promiseFn(0).then(
(res) => {
console.log("成功", res); // 真值結果
},
(rej) => {
console.log("失敗", rej); // 0 的結果
}
);

試著將 CodePen 中的參數改成真值0,就會在 console 中個別出現要接收的結果,這樣就可以直接使用 then() 來取得結果,就不用使用 catch() 了。

CodePen: https://codepen.io/hnzxewqw/pen/Rwazrba?editors=1111

Promise 常用方法

這兩個方法使用上有點像,只是取值的方式不同。

Promise.all()

全部同時執行,並且只要有一個是錯誤的,就會直接回傳錯誤給 catch 接收。

改寫原本的 promiseFn 函式,多加一個 time 的參數,若沒有傳值進去,預設就是 500 毫秒。

1
2
3
4
5
6
7
8
9
10
11
function promiseFn(num, time = 500) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (num) {
resolve(`success ${num}`);
} else {
reject("error");
}
}, time);
});
}

使用 Promise.all() 的方法,取得三次函式執行的結果。

1
2
3
4
5
6
7
Promise.all([promiseFn(1), promiseFn(2, 1000), promiseFn(3, 2000)])
.then((res) => {
console.log(res[0], res[1], res[2]); // success 1 success 2 success 3
})
.catch((rej) => {
console.log(rej);
});

將 2 改成 0,就會直接變成接收失敗的結果。

CodePen: https://codepen.io/hnzxewqw/pen/OJNeMmx?editors=1111

Promise.race()

全部同時執行,但只針對第一個回傳的值做為接收值,若第二或第三個有錯誤,則不影響回傳的結果。

all() 的方法改成 race(),並將回傳的結果稍微改寫。

1
2
3
4
5
6
7
8
9
10
11
Promise.race([
promiseFn(1, 500),
promiseFn(2, 300), // 會先取到這個結果
promiseFn(3, 2000),
])
.then((res) => {
console.log(res);
})
.catch((rej) => {
console.log(rej);
});

就算把 1 改成 0,也因為第二個執行時間比較早,所以第一個雖然值改成 0,也不會影響結果。

CodePen: https://codepen.io/hnzxewqw/pen/wvGLMqp?editors=1111