到2016年,Node自v4以来几乎已经完全支持ES6,而Promise自0.12以来一直存在。现在是时候把回调留在IMO尘埃中了。
我正在使用基于commander.js的CLI工具,它利用了很多异步操作 - http请求和用户输入。我希望将Commander action
包装在异步函数中,以便它们可以被视为promises,并且还支持生成器(对于我用于用户输入的co-prompt
库非常有用)。
我尝试用co
以两种方式包装CB:
1)
program.command('myCmd')
.action(program => co(function* (program) {...})
.catch(err => console.log(err.stack)) );
和
2)program.command('myCmd').action(co.wrap(function* (program) { .. }));
1)的问题是program
参数未通过
2)的问题是误吞了......
我真的很想让它工作,因为它在我的用例中产生了更好的代码 - 涉及大量的http请求,还等待使用co-prompt
库的用户输入..
或许以某种方式包裹program.Command.prototype.action
是一个更好的选择吗?
谢谢!
答案 0 :(得分:0)
我使用了co
之类的定制版本来获取db.exec
函数,该函数使用yield来执行数据库请求。您可以将参数传递给生成器函数(我传入连接对象 - 请参阅我所做的注释)。
这是db.exec函数,它与co
非常相似
exec(generator) {
var self = this;
var it;
debug('In db.exec iterator');
return new Promise((accept,reject) => {
debug('In db.exec Promise');
var myConnection;
var onResult = lastPromiseResult => {
debug('In db.exec onResult');
var obj = it.next(lastPromiseResult);
if (!obj.done) {
debug('db.exec Iterator NOT done yet');
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
debug('db.exec released connection');
}
accept(obj.value);
debug('db.exec Promise Resolved with value %d',obj.value);
}
};
self._connection().then(connection => {
debug('db.exec got a connection');
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
logger('database', 'Exec Function Error: ' + error.message);
reject(error);
});
});
}
连接对象也由数据库连接对象包装,并提供生成器函数处理数据库结果行的能力,但我不会在这里发布(尽管下面的示例使用它来处理行)。
以下是使用exec函数运行sql序列
的示例 db.exec(function*(connection) {
if (params.name === ADMIN_USER) {
debug('Admin Logon');
user.name = ADMIN_DISPLAY;
user.keys = 'A';
user.uid = 0;
let sql = 'SELECT passwordsalt FROM Admin WHERE AdminID = 0';
connection.request(sql);
yield connection.execSql(function*() {
let row = yield;
if (row) {
user.nopass = (row[0].value === null);
} else {
user.nopass = false;
}
debug('Admin Password bypass ' + user.nopass.toString());
});
} else {
debug('Normal User Logon');
let sql = `SELECT u.UserID,PasswordSalt,DisplayName,AccessKey,l.LogID FROM Users u
LEFT JOIN UserLog l ON u.userID = l.userID AND DATEDIFF(D,l.LogDate,GETDATE()) = 0
WHERE u.UserName = @username`;
let request = connection.request(sql);
request.addParameter('username',db.TYPES.NVarChar,params.name);
let count = yield connection.execSql(function*() {
let row = yield;
if (row) {
user.uid = row[0].value;
user.name = row[2].value;
user.keys = (row[3].value === null) ? '' : row[3].value;
user.nopass = (row[1].value === null) ;
user.lid = (row[4].value === null) ? 0 : row[4].value;
debug('Found User with uid = %d and lid = %d, keys = %s',
user.uid, user.lid, user.keys);
}
});
if (count === 0) {
debug('Not Found User');
// couldn't find name in database
reply(false,false);
return;
}
}
if (!user.nopass) {
debug('Need a Password');
//user has a password so we must check it
passGood = false; //assume false as we go into this
let request = connection.request('CheckPassword');
request.addParameter('UserID',db.TYPES.Int,user.uid);
request.addParameter('password',db.TYPES.VarChar,params.password);
yield connection.callProcedure(function*() {
let row = yield;
if (row) {
//got a valid row means we have a valid password
passGood = true;
}
});
} else {
passGood = true;
}
if (!passGood) {
debug('Not a Good Pasword');
reply(false,true);
} else {
if (user.uid !== 0 && user.lid === 0) {
let sql = `INSERT INTO UserLog(UserID,LogDate,TimeOn,UserName) OUTPUT INSERTED.logID
VALUES(@uid,GETDATE(),GETDATE(),@username)`;
let request = connection.request(sql);
request.addParameter('uid',db.TYPES.Int,user.uid);
request.addParameter('username',db.TYPES.NVarChar,user.name);
yield connection.execSql(function*() {
let row = yield;
if (row) {
user.lid = row[0].value;
debug('Users Log Entry = %d',user.lid);
}
});
}
reply(true,user);
}
})
.catch((err) => {
logger('database','Error on logon: ' + err.message);
reply(false,false);
});
});
答案 1 :(得分:0)
在 Commander.js 中有一个非常简单的方法来执行 async
函数
async function run() {
/* code goes here */
}
program
.command('gettime')
.action(run);
program.parse(process.argv);