วิธีจัดการกับการปฏิเสธสัญญาที่ไม่สามารถจัดการได้ในวิธีวัตถุ async ใน Node.js expressjs

ฉันใช้ฟังก์ชัน async ภายในวัตถุเพื่อส่งการตอบกลับใน express.js

รหัสตัวควบคุม:

module.exports = {

    async signUpEmail(req, res) {

        /**
         * @description Parameters from body
         * @param {string} firstName - First Name
         * @inner
         */  

        const firstName = req.body.firstName;

        res.send({ success: name });
        throw new Error(); // purposely Done
    }
}

คำถาม:

เนื่องจากเมธอด signUpEmail เป็นแบบอะซิงก์ในกรณีของฉัน และมันจะถูกปฏิเสธด้วยวิธี async ใดก็ตามของฉันที่นี่ มันมา Error (จงใจวางไว้ตรงนั้น)

ดังนั้นการเข้าสู่ระบบคอนโซลนี้

(node:13537) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error
(node:13537) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

ดังนั้นฉันควรจะจัดการมันจากเส้นทางที่ฉันเรียกมัน

รหัสเราเตอร์

    const routes = require('express').Router();
const SignUpController = require('../controllers/signUpController')

// /signup
routes.post('/', SignUpController.signUpEmail);

module.exports = routes;

บางอย่างแบบนี้ SignUpController.signUpEmail().then(…); แต่เนื่องจากฉันไม่ได้เรียกใช้ฟังก์ชันในเส้นทางที่ฉันเพิ่งผ่านไป สามารถทำได้อย่างมีประสิทธิภาพได้อย่างไร ?

PS: โปรดอย่าแนะนำวิธีแก้ปัญหาที่ซับซ้อนเกินไป ฉันเริ่มต้นด้วย JS และกำลังเรียนรู้ผ่าน

ฉันไม่ได้ใช้ตัวจัดการเส้นทางแบบ chainable เพราะฉันต้องการสร้างตัวจัดการเส้นทางแบบโมดูลาร์ที่สามารถติดตั้งได้

ตัวอย่างเอกสารอย่างเป็นทางการ


person Ankur Anand    schedule 22.04.2017    source แหล่งที่มา
comment
เพียงผ่านฟังก์ชันที่ทำ: routes.pos('/', (...args) => SignUpController.signUpEmail().then(…))   -  person Bergi    schedule 23.04.2017
comment
@Bergi รับสิ่งนี้ทันที TypeError: ไม่สามารถอ่านคุณสมบัติ 'เนื้อหา' ของไม่ได้กำหนด ดูเหมือนว่าสเปรดไม่ผ่าน req ..tried console.log ไม่ได้รับการกำหนด   -  person Ankur Anand    schedule 23.04.2017
comment
เดาว่าคุณจะต้องการ …signUpEmail(...args)… หรืออะไรก็ตามที่ฟังก์ชันของคุณคาดหวัง   -  person Bergi    schedule 23.04.2017
comment
@Bergi ใช่เข้าใจแล้ว .. หากคุณสามารถให้ความกระจ่างเล็กน้อยว่าทำไมวิธีนี้ถึงใช้งานได้โดยเฉพาะอย่างยิ่ง (...args) =› ใช้งานได้และนี่คืออะไร เพราะถ้าฉันทำ `routes.post('/', console.log(args));` ฉันได้รับสิ่งนี้ ReferenceError: args is not defined จะมีประโยชน์มาก   -  person Ankur Anand    schedule 23.04.2017
comment
คุณต้องใส่ไว้ในฟังก์ชันลูกศรเพื่อบันทึก แต่คุณยังสามารถเขียนได้โดยไม่ต้องมีพารามิเตอร์สเปรด: routes.post('/', (req, res) => SignUpController.signUpEmail(req, res).then(…))   -  person Bergi    schedule 23.04.2017
comment
@Bergi ตอนนี้ฉันคิดว่าฉันเข้าใจแล้ว (สเปรด) ทำให้ชัดเจนยิ่งขึ้น .. ไม่ทราบว่า js แพร่กระจายยังคงเรียนรู้ JS ดังนั้นโดยพื้นฐานแล้ว Route.post() จำเป็นต้องมีการโทรกลับ .. และเรากำลังทำการแก้ไขหรือปฏิเสธสัญญาที่ส่งคืนโดย SignUpController.signUpEmail(req, res) นี้และทำให้ผลลัพธ์ตามที่ส่งคืนโดยฟังก์ชันปกติ .. แก้ไขฉันด้วยถ้าฉันไม่เข้าใจ .. ขอบคุณสำหรับ ความช่วยเหลือที่ดี :)   -  person Ankur Anand    schedule 23.04.2017
comment
โปรดทราบว่า async/await ไม่ใช่ เป็นส่วนหนึ่งของ ES7 แต่เป็นส่วนหนึ่งของ ES2017   -  person Felix Kling    schedule 23.04.2017


คำตอบ (1)


ในเส้นทางของคุณ คุณจะต้องเพิ่ม wrapper เพื่อตรวจจับข้อผิดพลาดที่เกิดขึ้น:

let wrapper = fn => (...args) => fn(...args).catch(args[2]);

// /signup
routes.post('/', wrapper(SignUpController.signUpEmail));

ด้วยวิธีนี้ คุณสามารถใช้ตัวจับข้อผิดพลาดระดับบนสุด และไม่จำเป็นต้องใช้บล็อก try catch ภายในในเส้นทางของคุณ เว้นแต่ว่าคุณต้องการบล็อกตามบริบท

ใช้มิดเดิลแวร์จับข้อผิดพลาดเพื่อให้บรรลุเป้าหมายดังนี้:

// last middleware in chain

app.use(function(err, req, res, next) {
    // handle your errors
});

ตอนนี้ในเส้นทางของคุณ คุณสามารถโยนข้อผิดพลาดได้ และมิดเดิลแวร์นั้นจะดักจับได้ ฉันชอบที่จะโยนข้อผิดพลาดแบบกำหนดเองและจัดการการตอบสนองและการบันทึกในมิดเดิลแวร์นี้

นอกเหนือจาก: รูปแบบการรอแบบ async นั้นยอดเยี่ยมสำหรับการเขียนโค้ดแบบอะซิงโครนัสที่มนุษย์สามารถอ่านได้ง่ายในแบบซิงโครนัส เพียงจำไว้ว่าเมื่อคุณทำอะซิงก์แล้ว คุณควรคงอะซิงก์ไว้! แนะนำให้ใช้ไลบรารี Promisification เช่น Bluebird และการเรียกใช้ .promisifyAll บน nodeback ไลบรารี

แก้ไข: แหล่งที่มา - การจัดการข้อผิดพลาดแบบอะซิงโครนัสใน Express พร้อมสัญญา เครื่องกำเนิดไฟฟ้าและ ES7

person Kyle Richardson    schedule 22.04.2017
comment
อย่างแรกนั้นช่วยได้มากและเข้าใจมัน แต่สำหรับการใช้มิดเดิลแวร์ เราไม่ได้ผ่านขั้นตอนต่อไป (ผิดพลาด) ไปให้มันทำงานที่นี่ใช่ไหม - person Ankur Anand; 23.04.2017
comment
let wrapper = fn => (...args) => fn(...args).catch(args[2]); จับข้อผิดพลาดที่เกิดขึ้นจากฟังก์ชันภายใน wrapper และส่งคืนเป็นเส้นทางถัดไป ซึ่งจากนั้นจะถูกเลือกโดยข้อผิดพลาดในการจัดการมิดเดิลแวร์ของคุณ - person Kyle Richardson; 23.04.2017
comment
สิ่งนี้ตอบคำถามของคุณหรือไม่? - person Kyle Richardson; 23.04.2017