在没有回调地狱的情况下停止续集承诺链
Stop sequelize promise chain without call back hell
我刚开始使用node js,所以很可能我误解了"promise"和"callback hell"的概念。无论如何,我需要有关如何避免以下代码的建议:
var Sequelize = require('sequelize');
var DB = new Sequelize('project1db', 'john', 'password123', {
host: 'localhost',
dialect: 'mysql'
});
var DB_PREFIX = 't_';
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',{type: DB.QueryTypes.RAW})
.then(function(results) {
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
.then(function(results) {
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ')
.then(function(){
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
.then(function(){
// more queries
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
忽略我正在使用 SQL 创建表而不是使用 Sequelize 迁移脚本这一事实,因为我只是想说明我有很多 mysql 查询的观点应该 运行 串联。如果查询失败,那么我需要停止整个脚本并且不让后续的 .then()
函数触发。在我的 Sequelize 代码中,我通过嵌套大量原始查询函数调用以及 then 和 catch 语句来实现这一点。如果我有 100 个这样的嵌套回调语句,这将很难解决问题。
除了嵌套所有这些回调函数外,我还有其他选择吗?
您不是已经通过不使用迁移脚本来回答您自己的问题了吗?默认情况下,您需要 运行 迁移脚本来设置您的数据库并记录它,以便您了解迁移时间或上次迁移时间。
如果您需要顺序 SQL 命令,您仍然可以在 1 个命令内完成。查询将 运行 顺序进行。如果你想让每个 table 成为一个模型,为那个模型制作迁移脚本,不要这样做。
Sequelize 使用 bluebird
promises 库(的修改版本),这意味着这应该有效:
var Promise = Sequelize.Promise;
Promise.each([
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
], function runQuery(query) {
return DB.query(query, { type: DB.QueryTypes.RAW });
}).then(function() {
console.log('all done');
}).catch(function(err) {
console.log(err);
});
它使用 .each()
的静态版本,它将按顺序迭代数组项,将每个项传递给 runQuery
迭代器(returns 一个承诺),然后停止当承诺被拒绝时。
为了避免 "promise hell" - 这与 "callback hell" 是同一个问题 - 可以 return 每个 Promise 都在一个顶级的 thenable 中:
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',{type: DB.QueryTypes.RAW})
.then(function(results) {
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
}).then(function(results) {
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ')
}).then(function(){
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
}).then(function(){
// more queries
})
.catch(function(err){console.log(err);});
Promise 系统允许以这种方式进行链接,从而消除了对高级嵌套和缩进的需要。另请注意,只需要一个 catch - 如果一个 thenable 失败,它会跳到下一个可用的 catch()
.
我刚开始使用node js,所以很可能我误解了"promise"和"callback hell"的概念。无论如何,我需要有关如何避免以下代码的建议:
var Sequelize = require('sequelize');
var DB = new Sequelize('project1db', 'john', 'password123', {
host: 'localhost',
dialect: 'mysql'
});
var DB_PREFIX = 't_';
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',{type: DB.QueryTypes.RAW})
.then(function(results) {
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
.then(function(results) {
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ')
.then(function(){
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
.then(function(){
// more queries
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
}).catch(function(err){console.log(err);});
忽略我正在使用 SQL 创建表而不是使用 Sequelize 迁移脚本这一事实,因为我只是想说明我有很多 mysql 查询的观点应该 运行 串联。如果查询失败,那么我需要停止整个脚本并且不让后续的 .then()
函数触发。在我的 Sequelize 代码中,我通过嵌套大量原始查询函数调用以及 then 和 catch 语句来实现这一点。如果我有 100 个这样的嵌套回调语句,这将很难解决问题。
除了嵌套所有这些回调函数外,我还有其他选择吗?
您不是已经通过不使用迁移脚本来回答您自己的问题了吗?默认情况下,您需要 运行 迁移脚本来设置您的数据库并记录它,以便您了解迁移时间或上次迁移时间。
如果您需要顺序 SQL 命令,您仍然可以在 1 个命令内完成。查询将 运行 顺序进行。如果你想让每个 table 成为一个模型,为那个模型制作迁移脚本,不要这样做。
Sequelize 使用 bluebird
promises 库(的修改版本),这意味着这应该有效:
var Promise = Sequelize.Promise;
Promise.each([
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ',
], function runQuery(query) {
return DB.query(query, { type: DB.QueryTypes.RAW });
}).then(function() {
console.log('all done');
}).catch(function(err) {
console.log(err);
});
它使用 .each()
的静态版本,它将按顺序迭代数组项,将每个项传递给 runQuery
迭代器(returns 一个承诺),然后停止当承诺被拒绝时。
为了避免 "promise hell" - 这与 "callback hell" 是同一个问题 - 可以 return 每个 Promise 都在一个顶级的 thenable 中:
DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8;',{type: DB.QueryTypes.RAW})
.then(function(results) {
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'organization` ( ' +
'`organization_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
}).then(function(results) {
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'user_organization` ( ' +
'`user_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ')
}).then(function(){
return DB.query(
'CREATE TABLE IF NOT EXISTS `'+DB_PREFIX+'content` ( ' +
'`content_id` int(11) UNSIGNED NOT NULL ' +
') ENGINE=InnoDB DEFAULT CHARSET=utf8; ', {type:DB.QueryTypes.RAW})
}).then(function(){
// more queries
})
.catch(function(err){console.log(err);});
Promise 系统允许以这种方式进行链接,从而消除了对高级嵌套和缩进的需要。另请注意,只需要一个 catch - 如果一个 thenable 失败,它会跳到下一个可用的 catch()
.