node.js ~ построение цепочки последовательности Promise решает

Кто-нибудь может предложить лучший способ структурировать это использование Обещаний? Я новичок в Обещаниях и мне интересно, если я что-то упустил, как построить эту цепочку событий.

Примечание: Я НЕ намерен использовать здесь rej[ect]. То, что вы видите, соответствует только тому, что возвращается. Для кода, к которому он возвращается, нужен только один путь для обработки возвращаемого значения. Таким образом, возвращаемый код становится проще в своем потоке.

Это может помочь узнать, если вы не узнаете это, это взято из модуля, который я создал. Думайте об этом как о Дао.

module.exports = {

    dbConnection: function () {
        return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' };
    },


    CanIConnectToTheDB: function () {
        return new Promise(function (res, rej) {
            var sql = require('mssql');
            var myDao = require('./myDao');
            var cn = new sql.ConnectionPool(myDao.dbConnection());

            cn.connect().then(function () {
                var req = new sql.Request(cn);
                var qry = 'select serverproperty(\'productversion\') as \'rs\'';
                req.query(qry)
                    .then(function (rs) {
                        qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)';
                        req.query(qry)
                            .then(function (rss) {
                                res(' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS');
                            })
                            .catch(function (err) {
                                res(' CONNECTED// MASTER DB SUCCESS// ISSUE QUERYING MY DB //' + err + '//');
                            });
                    })
                    .catch(function (er) {
                        res(' CONNECTED// COULD NOT QUERY MASTER DB //' + er + '//');
                    });
            })
            .catch(function () {
                res(' CAN NOT CONNECT');
            });
        });
    }
};

2 ответа

Решение

Главное, что нужно помнить об обещаниях, это то, что then возвращает новое обещание (как и catch). Как будет выполнено это новое обещание, зависит от того, что вы возвращаете от обработчика: если вы возвращаете обещание, новое обещание от then/catch подчинен тому, кого вы вернули; если вы возвращаете значение, новое обещание разрешается с этим значением.

Таким образом, вы можете связать их вместе. Думать о then а также catch обработчики как преобразовательные фильтры, через которые проходит конечный результат.

Обратите внимание, что если у вас есть отправная точка, которая дает вам обещание (cn.connect()), вам не нужно new Promise: Просто используйте then а также catch преобразовать то, что проходит через цепочку, возвращая (новое) значение разрешения.

Еще одна ключевая вещь, которую нужно помнить, это catch Обработчик возвращает значение, он преобразует отклонение в разрешение. Чтобы продолжить путь отвержения, catch Обработчик должен либо сгенерировать исключение, либо вернуть обещание, которое будет / будет отклонено.

В заключение: require вызовы всегда должны быть в начале модуля.

Итак, не удаляя ваше преобразование отклонений в резолюции (подробнее об этом чуть позже):

var sql = require('mssql');
var myDao = require('./myDao');

module.exports = {

    dbConnection: function () {
        return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' };
    },


    CanIConnectToTheDB: function () {
        var cn = new sql.ConnectionPool(myDao.dbConnection());
        return cn.connect()
            .then(function () {
                var req = new sql.Request(cn);
                var qry = 'select serverproperty(\'productversion\') as \'rs\'';
                return req.query(qry)
                    .then(function (rs) {
                        qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)';
                        return req.query(qry)
                            .then(function (rss) { // Note you're not using rss anywhere
                                return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS';
                            })
                            .catch(function (err) {
                                return ' CONNECTED// MASTER DB SUCCESS// ISSUE QUERYING MY DB //' + err + '//';
                            });
                    })
                    .catch(function (er) {
                        return ' CONNECTED// COULD NOT QUERY MASTER DB //' + er + '//';
                    });
            })
            .catch(function() {
                return ' CAN NOT CONNECT';
            });
    }
};

Примечание: Я НЕ намерен использовать здесь rej[ect]. То, что вы видите, соответствует только тому, что возвращается. Для кода, к которому он возвращается, нужен только один путь для обработки возвращаемого значения. Таким образом, возвращаемый код становится проще в своем потоке.

Отказы идут по пути, отличному от решений, по причине. Это не усложняет, а упрощает. Не конвертируйте отклонения в резолюции, если вы не сделали какое-то исправление ошибок и можете продолжать, как если бы отклонение не произошло.

Вот тот код, где отклонениям разрешено быть отклонениями:

var sql = require('mssql');
var myDao = require('./myDao');

module.exports = {

    dbConnection: function () {
        return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' };
    },

    CanIConnectToTheDB: function () {
        var cn = new sql.ConnectionPool(myDao.dbConnection());
        return cn.connect()
            .then(function () {
                var req = new sql.Request(cn);
                var qry = 'select serverproperty(\'productversion\') as \'rs\'';
                return req.query(qry)
                    .then(function (rs) {
                        qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)';
                        return req.query(qry)
                            .then(function (rss) { // Note you're not using rss anywhere
                                return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS';
                            });
                    });
            });
    }
};

Используй это:

theModule.CanIConnectToTheDB()
    .then(function() {
        // Yes, let's do something
    })
    .catch(function() {
        // No, report the problem, etc.
    });

Я также, вероятно, выделю часть, которую, как я полагаю, вы будете выполнять снова и снова: установление соединения и получение от него объекта запроса:

var sql = require('mssql');
var myDao = require('./myDao');

function getRequest() {
    var cn = new sql.ConnectionPool(myDao.dbConnection());
    return cn.connect().then(function() {
        return new sql.Request(cn);
    });
}

module.exports = {

    dbConnection: function () {
        return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' };
    },

    CanIConnectToTheDB: function () {
        return getRequest().then(function(req) {
            var qry = 'select serverproperty(\'productversion\') as \'rs\'';
            return req.query(qry)
                .then(function (rs) {
                    qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)';
                    return req.query(qry)
                        .then(function (rss) { // Note you're not using rss anywhere
                            return ' CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS';
                        });
                });
        });
    }
};

Вместо чего-то вроде этого:

                .then(function (rs) {
                    qry = '...';
                    req.query(qry)
                        .then(function (rss) {

Вы можете использовать что-то вроде этого:

                .then(function (rs) {
                    qry = '...';
                    return req.query(qry);
                }).then(function (rss) {

Т.е. вы можете вернуть обещание в одном then Обратный звонок и получить разрешенное значение этого обещания в следующем then обратный вызов, поэтому ваш отступ остается постоянным.

Более простой пример - вместо этого:

a().then(va => {
    b(va).then(vb => {
        c(vb).then(vc => {
            // you can use vc here
        });
    });
});

ты можешь сделать:

a().then(va => {
    return b(va);
}).then(vb => {
    return c(vb);
}).then(vc => {
    // you can use vc here
});

Или даже проще, если вы используете async а также await:

va = await a();
vb = await b(va);
vc = await c(vb);
// you can use vc here

Обратите внимание, что вы можете использовать только await внутри функции, созданной с помощью async ключевое слово. В местах, где у вас нет собственной поддержки async а также await Вы можете использовать Babel или с немного другим синтаксисом подход на основе генератора, как в co или сопрограммы Bluebird. Для получения дополнительной информации и поддержки в браузерах и узлах, смотрите этот ответ:

Обновить

Это не проверено, но это примерно так:

module.exports = {

    dbConnection: function () {
        return { user: 'sa', password: 'mypassword', server: 'localhost', database: 'mydb' };
    },

    CanIConnectToTheDB: function () {
        var sql = require('mssql');
        var myDao = require('./myDao');
        var cn = new sql.ConnectionPool(myDao.dbConnection());
        var req;

        return cn.connect()
        .catch(err => Promise.reject('Error 1: ' + err))
        .then(() => {
            req = new sql.Request(cn);
            var qry = 'select serverproperty(\'productversion\') as \'rs\'';
            return req.query(qry)
                .catch(err => Promise.reject('Error 2: ' + err));
        }).then(rs => {
            var qry = 'select isnull(object_id(\'SomeObjectIKnowExists\'), -1)';
            return req.query(qry)
                .catch(err => Promise.reject('Error 3: ' + err));
        }).then(function (rss) {
            return 'CONNECTED// MASTER DB SUCCESS// MY DB SUCCESS';
        }).catch(err => {
            // if you want it always resolved:
            return 'CAN NOT CONNECT: ' + err;
        });
    }
};

Конечно, я хотел бы, чтобы окончательное обещание, возвращаемое этой функцией, было отклонено при ошибках и разрешено только при успехе, но, поскольку вы явно включили это странное требование в свой вопрос, я написал его так, как вы хотели.

Но если он отклонит обещание по любой ошибке, его будет гораздо проще использовать, особенно если все, что вас волнует, это ответ на вопрос в названии функции - Могу ли я подключиться к БД:

CanIConnectToTheDB()
    .then(() => console.log("Yes I can"))
    .catch(() => console.log("No I can't"));

Больше информации:

Для получения дополнительной информации см. Эти ответы:

Другие вопросы по тегам