紀錄幾個常見的 JS Promises!
Promise.all
Promise.all
一定要所有的 Promise 都被 resolved
才可以,不然會跳error,
但全部的Promise還是會完成執行
1 2 3 4 5 6 7 8 9 10 11 12 13
| const p1 = Promise.resolve('p1'); const p2 = new Promise((resolve, reject) => { setTimeout(() => reject('rejected p2'), 2000); }); const p3 = new Promise((resolve, reject) => { setTimeout(() => resolve('p3'), 3000); }); Promise.all([p1, p2, p3]) .then(console.log) .catch(console.error)
|
所以就會造成也許有些 Promise 其實是被 resolved
,
但卻因為其中一個 rejected
無法進行一般的結果處理,
而且收到error的時間點搞不好有些Promise還沒有執行完畢
這時候就可以考慮忽略error handling並改成以下寫法
(像是要關閉DB連線的時候,要等每一個Promise都真的處理完才可以關閉)
1 2 3 4 5 6 7 8
| Promise.all([ p1.catch(err => err), p2.catch(err => err), p3.catch(err => err) ]).then(console.log) .catch(console.error)
|
async / await
async / await
真是好東西,尤其是寫到一堆promise的時候快分不清楚誰是誰的時候(?)
不過要記住 async function 回傳的一定是一個 Promise,
而且要用 await 的話一定要用 async function 包住,
不能中途冒出一個 const fulfilledPromise = await request("/some/promise")
1 2 3 4 5 6 7 8 9 10 11 12
| async function greetFromAjaxRequest(name) { try { const greeting = await request("/hi/from/somewhere"); return `${greeting}, ${name}!`; } catch (error) { throw Error('Oops, something wrong!'); } } greetFromAjaxRequest("Trina") .then(console.log) .catch(console.error)
|
多個 await
如果有多個await放在一起,
它就會照著順序等到上一個promise resolved了以後,才會執行
所以可以拿來chaining
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const moment = require('moment'); const p1 = () => Promise.resolve('p1'); const p2 = (p1) => new Promise((resolve, reject) => { setTimeout(() => { console.log(moment() + ' resolve p2', 'result from p1:', p1); resolve('p2'); }, 5000); }); const p3 = (p2) => new Promise((resolve, reject) => { setTimeout(() => { console.log(moment() + ' resolve p3', 'result from p2:', p2); resolve('p3'); }, 2000); }); async function multiAwait() { try { const rp1 = await p1(); console.log(moment() + ' rp1'); const rp2 = await p2(rp1); console.log(moment() + ' rp2'); const rp3 = await p3(rp2); console.log(moment() + ' rp3'); return 'all promises resolved'; } catch (e) { console.log('err', e); } }
|
執行
1
| multiAwait().then(console.log);
|
會出以下結果:
1 2 3 4 5 6
| 1501754077891 rp1 1501754082894 resolve p2 1501754082895 rp2 1501754084895 resolve p3 1501754084896 rp3 all promises resolved
|
多個 await but 先跑 promise
下面的 p1
, p2
, p3
其實在起始的時候就已經執行了
(因為它不是return一個promise,而是直接 new 一個promise)
所以跟 promise chaining 沒有關係
但除了await
以外的部分
還是會等到它自己之前的promise都resolved了之後才會執行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const moment = require('moment'); const p1 = Promise.resolve('p1'); const p2 = new Promise((resolve, reject) => { setTimeout(() => { console.log(moment() + ' resolve p2'); resolve('p2'); }, 5000); }); const p3 = new Promise((resolve, reject) => { setTimeout(() => { console.log(moment() + ' resolve p3'); resolve('p3'); }, 2000); }); async function multiAwait() { try { const rp1 = await p1; console.log(moment() + ' rp1'); const rp2 = await p2; console.log(moment() + ' rp2'); const rp3 = await p3; console.log(moment() + ' rp3'); return 'all promises resolved'; } catch (e) { console.log('err', e); } }
|
執行
1
| multiAwait().then(console.log);
|
會出以下結果:
1 2 3 4 5 6
| 1501211897186 rp1 1501211899171 resolve p3 // after 2 secs 1501211902171 resolve p2 // after 5 secs 1501211902171 rp2 1501211902172 rp3 // p3 兩秒後就 resolved 了,但因為程式碼順序(?)的關係,要等到 p1, p2, p3 都 resolved 之後才會被執行 all promises resolved
|
Chaining
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function promiseFactory(sec, index) { return new Promise((resolve, reject) => { setTimeout(() => resolve("promise " + index + " resolved in " + sec + "at" + Math.round(new Date().getTime() / 1000)), sec); }); } const myPromises = [ () => promiseFactory(1000, 1), () => promiseFactory(1000, 2), () => promiseFactory(1000, 3) ]; myPromises.forEach(promise => { promise().then(console.log); }); for (let promise of myPromises) { promise().then(console.log); } myPromises.reduce((resolved, promise) => { return resolved.then(promise).then(console.log); }, Promise.resolve('ok'));
|