Javascript обещаний: UnhandledPromiseRejectionWarning - PullRequest
0 голосов
/ 01 марта 2020

Я новичок в Javascript Обещаниях. Я пытаюсь выполнить запрос MySQL в стиле Promises. Я почесал голову более получаса, но все еще не могу найти проблему в этом коде. Я использую эту статью в качестве ссылки.

mysql file

const mysql = require('mysql')
const Config = require('./Config.js');

let connection = mysql.createPool({
    connectionLimit: Config.mysql.connectionLimit,
    host:   Config.mysql.host,
    user: Config.mysql.user,
    password: Config.mysql.password,
    database: Config.mysql.database,
    multipleStatements: true,
});

module.exports = {
    query: function(query, binds) {
        return new Promise((resolve, reject)=>{
            connection.query(query, binds, (error, ret)=>{
                if(error)
                    return reject(error);
                else
                    resolve(ret);
            })
        })
    },

    close: function() {
        return new Promise((resolve, reject)=>{
            connection.end((error)=>{
                if(error)
                    return reject(error);
                else
                    resolve();
            });
        });
    }
}

фактический сценарий

const Mysql = require('mysql file');

try {

Mysql.query("SELECT `password` \
            FROM `m_users` \
            WHERE `email` = ?", 
            ['user@domain.tld'])
    .then(ret=>{
        if(ret.email)
            return res.send({
                params: req.body,
                message: 'Email address has already been taken.',
            })
    })
    .catch(error=>{
        throw error;

    })

catch( e )
{
    console.log(e); // is never reached
}

throw error никогда не срабатывает. Вместо этого в консоли моего узла я получаю следующую ошибку:

(узел: 8684) UnhandledPromiseRejectionWarning: Ошибка: ER_NO_SUCH_TABLE: таблица 'forge.m_users' не существует

... ..... обратная трассировка здесь .......

(узел: 8684) UnhandledPromiseRejectionWarning: необработанное отклонение обещания. Эта ошибка возникла либо из-за того, что внутри asyn c -функции возникла ошибка без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch (). (идентификатор отклонения: 1)

Я знаю, что таблица не существует. Мне интересно узнать, почему .catch не обрабатывает ошибку. Что я делаю неправильно? : /

Ответы [ 2 ]

2 голосов
/ 01 марта 2020

Это анти-паттерн (но вы не на сегодняшний день первый человек, который это сделает!):

.catch(error=>{
    throw error;

})

Что говорит «Создайте новое обещание» «(потому что catch создает обещание)» и если первоначальное обещание отклоняется, отклоните его с точно такой же причиной отказа (error). » Так что это в основном неоперация, она ничего не делает. Это эквивалент обещания:

try {
    // something
} catch (error) {
    throw error;
}

Поскольку он ничего не делает, подумайте, как выглядит код без него - код нарушает одно из фундаментальных правил обещаний, а именно «обрабатывать отклонения или передать цепь чему-то еще, что будет ". : -)

Если вы хотите справиться с отклонением, не throw из catch:

Mysql.query("SELECT `password` \
        FROM `m_users` \
        WHERE `email` = ?", 
        ['user@domain.tld'])
.then(ret=>{
    if(ret.email) {
        return res.send({
            params: req.body,
            message: 'Email address has already been taken.',
        });
    }
})
.catch(error=>{
    // Use `error` here without `throw`ing -- report it, put it in a log, etc.
});

В обновлении вопроса вы показываете, что у вас есть все Ваш код, использующий обещания в try / catch:

try {
    Mysql.query(/*...*/)
    .then(/*...*/)
    .catch(error=>{
        throw error;
    });
}
catch( e )
{
    console.log(e); // is never reached
}

В функции, отличной от async, try / catch не может отловить отклонения обещания, поскольку Когда обещание отклонено, исполнение уже покинуло блок try. При непосредственном использовании обещаний вы используете метод catch. Или вы используете функции async (подробнее ниже).


Примечание: Node.js уже некоторое время поддерживает async функции, которые, как правило, проще писать. В функции async ваш код может быть:

// Within an `async` function
try {
    const ret = await Mysql.query("SELECT `password` \
            FROM `m_users` \
            WHERE `email` = ?", 
            ['user@domain.tld']);
    if(ret.email) {
        return res.send({
            params: req.body,
            message: 'Email address has already been taken.',
        });
    }
} catch (error) {
    // Use `error` here without `throw`ing -- report it, put it in a log, etc.
}

Использование async на верхнем уровне модуля также скоро появится ...


В комментарии вы спросили:

Я создаю MVC API и запускаю больше процедур на основе обещаний в том же методе контроллера. Я хотел бы вернуть сообщение, как только возникнет исключение, и прекратить продолжать выполнение следующих других обещанных процедур. Я обязан использовать метод async / await или есть другой способ?

Вам не нужно использовать async / await, если вы не хотите, нет; они просто делают вещи проще (на мой взгляд).

Если вы не хотите использовать async / await, в обратном вызове выполнения вы передаете then, return обещание от следующей операции. Это заставляет обещание then исполнять или отклонять в зависимости от того, что обещание выполняет следующая операция - в жаргоне обещания разрешает обещание от then до , полученное от следующая операция.

Код стоит 1024 слова, поэтому:

doSomethingAsync()
.then(value => {
    // ...use `value`, then
    return doSomethingElseAsync();
})
.then(() => {
    // ...
    return doYetAnotherAsyncThing();
})
.catch(error => {
    // Handle/report error here
});

Если любое из обещаний отклонено, любые последующие обработчики выполнения пропускаются, а обработчик отклонения в конце (добавляется через catch) срабатывает.

Это примерно обещанная версия этого синхронного кода:

try {
    const value = doSomethingSync();
    // ...use `value`, then
    doSomethingElseSync();
    // ...
    doYetAnotherSyncThing();
} catch (error) {
    // Handle/report error here
}
1 голос
/ 01 марта 2020

По сути, причина того, что вы получаете необработанное отклонение, заключается в смешении асин c и кода syn c - обещания асинхронны и try{ ... } catch() { ... } работают только в синхронном режиме. вызов асинхронной функции в синхронном блоке try-catch не ожидает его завершения. попытайтесь обернуть ваше обещание async/await или обработайте отклонение в .catch() самого обещания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...