คำตอบของเบนจามินเสนอสิ่งที่เป็นนามธรรมสำหรับการแก้ปัญหานี้ แต่ฉันหวังว่าจะได้ข้อสรุปที่เป็นนามธรรมน้อยกว่า วิธีที่ชัดเจนในการแก้ไขปัญหานี้คือเพียงแค่โทรหา.catch
สัญญาภายในและส่งกลับข้อผิดพลาดจากการโทรกลับ
let a = new Promise((res, rej) => res('Resolved!')),
b = new Promise((res, rej) => rej('Rejected!')),
c = a.catch(e => { console.log('"a" failed.'); return e; }),
d = b.catch(e => { console.log('"b" failed.'); return e; });
Promise.all([c, d])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));
Promise.all([a.catch(e => e), b.catch(e => e)])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));
เมื่อก้าวต่อไปอีกหนึ่งขั้นคุณสามารถเขียนตัวจัดการแบบทั่วไปที่มีลักษณะดังนี้:
const catchHandler = error => ({ payload: error, resolved: false });
จากนั้นคุณสามารถทำได้
> Promise.all([a, b].map(promise => promise.catch(catchHandler))
.then(results => console.log(results))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!', { payload: Promise, resolved: false } ]
ปัญหาของเรื่องนี้ก็คือค่าที่ถูกจับจะมีส่วนต่อประสานที่แตกต่างจากค่าที่ไม่ถูกดักจับดังนั้นหากต้องการล้างข้อมูลนี้คุณอาจทำสิ่งต่อไปนี้:
const successHandler = result => ({ payload: result, resolved: true });
ดังนั้นตอนนี้คุณสามารถทำสิ่งนี้:
> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]
จากนั้นเพื่อให้มันแห้งคุณจะได้รับคำตอบของเบนจามิน:
const reflect = promise => promise
.then(successHandler)
.catch(catchHander)
ตอนนี้ดูเหมือนว่าที่ไหน
> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]
ประโยชน์ของการแก้ปัญหาที่สองคือมันเป็นนามธรรมและแห้ง ข้อเสียคือคุณมีรหัสมากขึ้นและคุณต้องจำไว้เพื่อสะท้อนถึงสัญญาทั้งหมดของคุณเพื่อให้สิ่งต่าง ๆ สอดคล้องกัน
ฉันจะอธิบายลักษณะการแก้ปัญหาของฉันอย่างชัดเจนและจูบ แต่แน่นอนน้อยกว่าที่แข็งแกร่ง อินเทอร์เฟซไม่รับประกันว่าคุณจะรู้ว่าสัญญาสำเร็จหรือล้มเหลว
ตัวอย่างเช่นคุณอาจมีสิ่งนี้:
const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));
สิ่งนี้จะไม่ถูกดักจับa.catch
ดังนั้น
> Promise.all([a, b].map(promise => promise.catch(e => e))
.then(results => console.log(results))
< [ Error, Error ]
ไม่มีวิธีใดที่จะบอกได้ว่าอันใดที่เป็นอันตรายถึงชีวิต ถ้านั่นเป็นสิ่งสำคัญคุณจะต้องบังคับใช้และอินเทอร์เฟซที่ติดตามว่ามันสำเร็จหรือไม่ (อันreflect
ไหน)
หากคุณต้องการจัดการข้อผิดพลาดอย่างสง่างามคุณสามารถจัดการกับข้อผิดพลาดเป็นค่าที่ไม่ได้กำหนด:
> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
.then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]
ในกรณีของฉันฉันไม่จำเป็นต้องรู้ข้อผิดพลาดหรือความล้มเหลว - ฉันแค่ใส่ใจว่าฉันมีคุณค่าหรือไม่ ฉันจะให้ฟังก์ชั่นที่สร้างความกังวลในการบันทึกข้อผิดพลาดเฉพาะ
const apiMethod = () => fetch()
.catch(error => {
console.log(error.message);
throw error;
});
ด้วยวิธีดังกล่าวส่วนที่เหลือของแอปพลิเคชันสามารถเพิกเฉยต่อข้อผิดพลาดได้หากต้องการและถือว่าเป็นค่าที่ไม่ได้กำหนดหากต้องการ
ฉันต้องการฟังก์ชั่นระดับสูงของฉันที่จะล้มเหลวได้อย่างปลอดภัยและไม่ต้องกังวลเกี่ยวกับรายละเอียดเกี่ยวกับเหตุผลที่พึ่งพาล้มเหลวและผมยังชอบจูบให้แห้งเมื่อฉันมีที่จะทำให้ที่ถ่วงดุลอำนาจ - reflect
ซึ่งท้ายที่สุดก็คือเหตุผลที่ผมเลือกที่จะไม่ใช้