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"));
Больше информации:
Для получения дополнительной информации см. Эти ответы:
- Как конвертировать метод Водопад в обещание
- jQuery: возвращать данные после успешного вызова ajax (см. пояснения в обновлениях к этому ответу).