[英]Using Q promises - is there a way to make this code less repetitive?
我正在为我的Node.js应用程序启动集成测试套件。 我目前正在尝试编写一个安装脚本,该脚本擦除测试数据库并用一些测试数据填充它。 我试图避免可怕的“末日金字塔” ,我希望使用promise作为防止我的代码失控的一种方式。 我对诺言很陌生,但我仍在努力将诺言缠住-可能是我没有正确使用诺言。
这是我没有承诺的初始版本。 这可行,但是在wazoo中嵌套了回调:
var mongoose = require('mongoose');
var User = require('./user');
var MONGODB_URL = process.env.MONGODB_TEST_URL || 'localhost:27017/swot_test';
console.log('\nRunning e2e test preparation script');
console.log('-----------------------------------\n');
console.log('Connecting to database:', MONGODB_URL, '...')
mongoose.connect(MONGODB_URL, function () {
console.log('Wiping database...')
mongoose.connection.db.dropDatabase(function () {
console.log('Setting up test user...')
User.createUser({
email: 'test@example.com',
password: 'tester'
}, function (err, user) {
if (err) throw err;
// If there was more setup, it would have to go here... pyramid of doom!
console.log('Finished.');
process.exit();
});
});
});
这是使用Q promises的版本:
var Q = require('q');
var mongoose = require('mongoose');
var User = require('./user');
var MONGODB_URL = process.env.MONGODB_TEST_URL || 'localhost:27017/swot_test';
console.log('\nRunning e2e test preparation script');
console.log('-----------------------------------\n');
Q.fcall(function () {
var deferred = Q.defer();
console.log('Connecting to database:', MONGODB_URL, '...');
mongoose.connect(MONGODB_URL, function (err) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Wiping database...');
mongoose.connection.db.dropDatabase(function (err) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Setting up test user...');
User.createUser({
email: 'test@example.com',
password: 'tester'
}, function (err, user) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.done(function () {
console.log('Finished.');
process.exit();
}, function (err) {
console.error('An error occurred:', err.stack);
});
我喜欢它的嵌套少,但是里面有很多重复。 有没有一种方法可以使用Q API中的辅助函数使此代码更简洁,更不重复? 特别是这部分:
if (err) deferred.reject(new Error(err));
else deferred.resolve();
我将不胜感激清理此代码。
Q.ninvoke(mongoose,'connect', MONGODB_URL)
.then(function () {
console.log('Wiping database...');
return Q.ninvoke(mongoose.connection.db, 'dropDatabase');
})
.then(function () {
console.log('Setting up test user...')
return Q.ninvoke(User, 'createUser', {
email: 'test@example.com',
password: 'tester'
});
})
.then(function (user) {
console.log('Finished.');
process.exit();
})
.catch(function(err) {
console.log(err);
});
您可以使用可重复使用的oncomplete
助手来缩短它,如下所示:
function oncomplete(deferred) {
return function (err, result) {
if (err) deferred.reject(new Error(err));
else deferred.resolve(result);
}
}
Q.fcall(function () {
var deferred = Q.defer();
console.log('Connecting to database:', MONGODB_URL, '...');
mongoose.connect(MONGODB_URL, oncomplete(deferred));
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Wiping database...');
mongoose.connection.db.dropDatabase(oncomplete(deferred));
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Setting up test user...');
User.createUser({
email: 'test@example.com',
password: 'tester'
}, oncomplete(deferred));
return deferred.promise;
})
.done(function () {
console.log('Finished.');
process.exit();
}, function (err) {
console.error('An error occurred:', err.stack);
});
如果您足够勇敢,可以使用Node v0.11 beta和yield
关键字彻底简化它。 那将实现一个异步状态机,因此您可以使用伪线性代码流而无需显式回调。
检查async
模块,特别是waterfall
。 你可以在这里读到它:
https://github.com/caolan/async#waterfalltasks-callback
基本上,它允许您以一种简洁的方式链接一组嵌套的回调。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.