一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

解决nodejs搭配express、mongoose异步流程问题解决办法

时间:2015-02-02 编辑:简简单单 来源:一聚教程网

1、引子

在 node 端,express 的 HTTP 启动和 mongoose 的 mongodb 连接都是异步的,因此会遇到,打开网站时,数据库还没有连上,导致查询错误,或者遇到数据库已经连接上了,但 HTTP 服务已经启动失败了。

还有更复杂一点的使用场景:首先链接数据库,然后是中间件(比如查询固定配置,如网站标题、管理员信息、oauth配置等不需要变更的配置,但需要存储再数据库的配置,因为源代码是公开在 github 上的,目前作者的需求就是这样的),最后启动 HTTP 服务器。

关于这个启动过程,虽然有些麻烦,但还是在 node 端异步情况下,经常出现的。比如(此处仅为示例),查询3个用户,然后分别查询这个3个用户发布文章的数量,以及这3个用户关注的主题。看上去是不是很复杂?

以上,如果你觉得很简单的话,那么可以到此为止了。

2、使用howdo来处理异步串行

2.1、express + mongoose

如果启动只需要这两样的话,那么不需要担心,直接这样:

var howdo = require('howdo');
/**
 * 启动 HTTP 服务
 * @param callback {Function} 回调
 */
var express = function (callback) {
    var app = require('express')();
    app.listen(80, callback);
};
/**
 * 连接数据库
 * @param callback {Function} 回调
 */
var mongoose = function (callback) {
    var mongoose = require('mongoose');
    mongoose.connect('mongodb://localhost:27017/some-table');
    mongoose.connection.on('connected', callback);
    mongoose.connection.on('error', callback);
    mongoose.connection.on('disconnected', callback);
};
/**
 * 异步并行
 */
howdo.task(express).task(mongoose).together(function (err) {
    if (err) {
        console.error(err);
        process.exit(-1);
    }
    console.log('');
    console.log('#########################################################');
    console.log('http server running at 80');
    console.log('#########################################################');
    console.log('');
});

2.2、express+mongoose+middleware

源码如下(很直观):

var howdo = require('howdo');
/**
 * 实例化 express
 * @param callback {Function} 回调
 */
var express = function (callback) {
    var app = require('express')();
    callback(null, app);
};
/**
 * 连接数据库
 * @param callback {Function} 回调
 * @param app {Object} express 实例
 */
var mongoose = function (callback, app) {
    var mongoose = require('mongoose');
    var proxyCallback = function (err) {
        callback.call(global, err, next, app);
    };
    mongoose.connect('mongodb://localhost:27017/some-table');
    mongoose.connection.on('connected', proxyCallback);
    mongoose.connection.on('error', proxyCallback);
    mongoose.connection.on('disconnected', proxyCallback);
};
/**
 * 中间件
 * @param callback {Function} 回调
 * @param app {Object} express 实例
 */
var middleware = function (callback, app) {
    var someModel = require('path/to/model');
    someModel.getConfig(function (err, configs) {
        if (err) {
            return callback(err);
        }
        app.locals._configs = configs;
        callback(err, app);
    });
};
/**
 * 启动 HTTP 服务
 * @param callback {Function} 回调
 * @param app {Object} express 实例
 */
var http = function (callback, app) {
    app.listen(80, callback);
}
/**
 * 异步串行
 */
howdo
    .task(express)
    .task(mongoose)
    .task(middleware)
    .task(http)
    .follow(function (err) {
        if (err) {
            console.error(err);
            process.exit(-1);
        }
        console.log('');
        console.log('#########################################################');
        console.log('http server running at 80');
        console.log('#########################################################');
        console.log('');
    });

3、数据库查询综合

看起来比较复杂:

var howdo = require('howdo');
var userMode = require('path/to/user-model');
var postMode = require('path/to/post-model');
var followMode = require('path/to/follow-model');
/**
 * 查询 3 个用户
 * @param callback {Function} 完成回调
 */
var getThreeUsers = function (callback) {
    userMode.getUsers(10, callback);
};
/**
 * 查询 1 个用户的文章信息
 * @param user {Object} 用户信息
 * @param callback {Function} 完成回调
 */
var getUserPosts = function (user, callback) {
    postMode.getUserPosts(user, callback);
};
/**
 * 查询 1 个用户的关注信息
 * @param user {Object} 用户信息
 * @param callback {Function} 完成回调
 */
var getUserFollows = function (user, callback) {
    followMode.getUserFollows(user, callback);
};
/**
 * 读取所有用户的文章信息
 * @param users {Array} 用户列表数组
 * @param callback {Function} 完成回调
 */
var getUsersPosts = function (users, callback) {
    // 读取用户的文章信息
    howdo.each(users, function (index, user, done) {
        getUserPosts(user, done);
    }).together(function (err, user0Posts, user1Posts, user2Posts) {
        if (err) {
            return callback(err);
        }
        var postsList = Array.prototype.slice.call(arguments, 1);
        // 写入用户的文章信息
        postsList.forEach(function (posts, index) {
            users[index].posts = posts;
        });
        callback(null, users);
    });
};
/**
 * 读取所有用户的关注信息
 * @param users {Array} 用户列表数组
 * @param callback {Function} 完成回调
 */
var getUsersFollows = function (users, callback) {
    // 读取用户的关注信息
    howdo.each(users, function (index, user, done) {
        getUserFollows(user, done);
    }).together(function (err, user0Follows, user1Follows, user2Follows) {
        if (err) {
            return callback(err);
        }
        var followsList = Array.prototype.slice.call(arguments, 1);
        // 写入用户的文章信息
        followsList.forEach(function (follows, index) {
            users[index].follows = follows;
        });
        callback(null, users);
    });
};
howdo
    .task(getThreeUsers)
    .task(function (next, users) {
        howdo
            .task(function (done) {
                getUserPosts(users, done);
            })
            .task(function (done) {
                getUsersFollows(users, done);
            })
            // 异步并行
            .together(next);
    })
    // 异步并行
    .follow(function (err, users) {
        if (err) {
            console.error(err);
            process.exit(-1);
        }
        // 组装好后的 users 对象
        console.log(users);
    });

热门栏目