繁体   English   中英

使用Q promises-有没有办法使此代码的重复性降低?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM