跳到主要内容
CNode

轻松给mongoose添加jscex的语法糖

社区
Hhpf1908发布于 14 年前最后回复 14 年前
977480

今天下午捣鼓了一下小应用,使用老赵的jscex给mongoose添加了Async 同步方法,感觉还不错,至少对我来说相当节省开发效率,分享一下。

给mongoose添加jscex的方法很简单,只需要使用老赵的 ”Jscex异步增强模块“进行异步操作绑定即可,什么是”Jscex异步增强模块“在此我就不缀述了,感兴趣的同学直接访问 Jscex异步增强模块 即可。这里仅贴出mongoose的异步操作绑定代码,代码比较简单,就不一一说明了。

先贴一个加载异步增强模块的代码,我事先用npm安装了jscex,命令如下” npm install jscex jscex-jit jscex-async”,详细请看赵姐夫的说明,链接地址:https://github.com/JeffreyZhao/jscex/blob/master/README-cn.md

var Jscex = require("jscex");

require("jscex-jit").init(Jscex);
require("jscex-async").init(Jscex);
require("./jscex-async-powerpack").init(Jscex);

module.exports = Jscex;

有了jscex,剩下就是加语法糖的代码了,只需做个简单的绑定

var mongoose = require('mongoose'),
    Jscex = require('../plugins/jscex-start'),
    Model = mongoose.Model;
 
var Async = Jscex.Async;
var Task = Async.Task;
var Jscexify = Async.Jscexify;
 
//真坑爹,mardown居然有小于号就显示不正确
var addSugarMethods = function(methods , obj){
    for(var i = 0,len = methods.length; i 小于 len ; i++){
        if(obj[methods[i]])
            obj[methods[i] + 'Async'] = Jscexify.fromStandard(obj[methods[i]]);
    }
}
 
module.exports = {
    init : function(){
        addSugarMethods(['save','remove'],Model.prototype);
    },
    model : function(name ,schema){
        mongoose.model(name, schema);
        var methods = ['find','remove','findById','findOne','count','distinct','create','update'];
        var model = mongoose.model(name);
        addSugarMethods(methods,model);
    }
}
	

好了,下面以node-club源码里的User 对象做个例子测试一下

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var modelAsync = require('./modelAsync');
	
var UserSchema = new Schema({
	//用户昵称
	name: { 
		type: String, 
		index: true 
	},      
	//用户登录名称:唯一
	loginname: { 
		type: String 
	},
	//登录密码
	pass: { 
		type: String 
	},
	//邮箱
	email: { 
		type: String 
	},
	//个人主页
	url: { 
		type: String 
	},
	//住址
	location: { 
		type: String 
	},
	//个性签名
	signature: { 
		type: String 
	},
	//个人简介
	profile: { 
		type: String 
	},
	//微薄
	weibo: { 
		type: String 
	},
	//头像
	avatar: { 
		type: String 
	},
	//被关注的人数
	follower_count: { 
		type: Number, 
		default: 0 
	},
	//关注的人数
	following_count: { 
		type: Number, 
		default: 0 
	},
	//创建时间
	create_at: { 
		type: Date, 
		default: Date.now 
	},
	//更新时间
	update_at: { 
		type: Date, 
		default: Date.now 
	},
	//是否活动状态
	active: { 
		type: Boolean, 
		default: true 
	}
});

modelAsync.model('User', UserSchema);

----------------------分割线----------------------------------

var mongoose = require('mongoose'),
    config= require('../config').config,
    modelAsync = require('./modelAsync');
 
modelAsync.init();
 
mongoose.connect(config.db, function(err){
    if(err){
        console.log('connect to db error: ' + err.message);
        process.exit(1);
    }
});
 
// models
require('./user');
 
exports.User = mongoose.model('User');

上面代码取自node-club里的源码,至此就可以用同步的写法去获取数据了,测试代码如下

var models      = require('../../models'),
    User = models.User,
    should = require('should'),
    Jscex = require('../../plugins/jscex-start');
 
module.exports = {
 
  'test updating documents async': function () {
 
        var saveUserAsync = eval(Jscex.compile("async", function (user) {
            $await(user.saveAsync());
            var _user = $await(User.findAsync({ _id : user._id }));
            should.exist(_user);
            _user.should.have.length(1);
        }));
 
        var user = new User();
 
        user.name      = 'flyhuang';
        user.loginname = 'hpf1908';
        user.pass      = '123456';
        user.email     = 'hpf1908[@gmail](/user/gmail).com';
 
        var task = saveUserAsync(user);
        task.start();
    },
    'test delete documents async' : function(){
 
        var removeUserAsync = eval(Jscex.compile("async", function (user) {
            $await(user.saveAsync());
            $await(User.removeAsync({ name : user.name }));
            var _user = $await(User.findAsync({ name : user.name }));
            _user.should.be.empty;
        }));
 
        var user = new User();
 
        user.name      = 'flyhuang';
        user.loginname = 'hpf1908';
        user.pass      = '123456';
        user.email     = 'hpf1908[@gmail](/user/gmail).com';
 
        var task = removeUserAsync(user);
        task.start();
    }
}

看上面的例子是否觉得同步写法更简明易懂了?当然如果你不喜欢这样的写法也可以继续使用异步的方式,再贴一个用异步写法的例子,以作对比

var models      = require('../../models'),
    User = models.User,
    should = require('should');
 
module.exports = {
 
  'test updating documents': function () {
 
        var user = new User();
 
        user.name      = 'flyhuang';
        user.loginname = 'hpf1908';
        user.pass      = '123456';
        user.email     = 'hpf1908[@gmail](/user/gmail).com';
 
        user.save(function (err) {
            should.strictEqual(err, null);
            User.find({ _id : user._id },function(err , user){
                should.strictEqual(err, null);
                should.exist(user);
                user.should.have.length(1);
 
                console.log('done');
            });
        });
    },
    'test delete documents' : function(){
        var user = new User();
 
        user.name      = 'flyhuang';
        user.loginname = 'hpf1908';
        user.pass      = '123456';
        user.email     = 'hpf1908[@gmail](/user/gmail).com';
 
        user.save(function (err) {
            should.strictEqual(err, null);
            User.remove({ name : 'flyhuang' },function(err ){
                should.strictEqual(err, null);
                User.find({ name : 'flyhuang'},function(err , user){
                    should.strictEqual(err, null);
                    user.should.be.empty;
                    console.log('done');
                });
            });
        });
    }
}
查看回复

回复 (9)

H
hpf1908#814 年前
引用 jeffz不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪...

@jeffz 不是返回数组,像这样 var result = splitAsync(xxx); result._data = []; 除了显示设值外还另外把所有返回值做成数组形式挂在_data 下,这样的话给异步方法绑定同步写法,我就可以直接用fromCallback 就可以去取到所有返回值,当然你说的那样可读性更好也规范

J
jeffz#714 年前
引用 jeffz不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪...

@hpf1908 链式语法早就支持了吧,你只要补个on就行了,作为addEventListener的别名。

你是指Task自动返回个数组?主要我是想用名字来访问数据,不要用下标,用起来更方便。

H
hpf1908#614 年前
引用 jeffz不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪...

@jeffz 恩,更新了通知一声,链式语法还是比较习惯的,另外异步增强里的fromCallback,我希望直接在返回值里挂一个叫_arguments的变量,这样我就不需要硬编码var splitAsync = Jscexify.fromCallback(split, "equals", "larger", "smaller"),取equals这种值

J
jeffz#514 年前
引用 jeffz不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪...

@hpf1908 其实要切换什么跟普通异步事件也没什么两样:

somethingAsync().on("complete", function () {
    if (this.error) { ... } else { ... }
});

Task.prototype上补个on什么的是顺手的事情,你会发现和其他异步编程基本没区别。

H
hpf1908#414 年前
引用 jeffz不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪...

@jeffz 我觉得如果只有一两个回调的情况用的话确实很绕,不太适用,但是如果回调嵌套很深的话用起来还比较爽,我就可以专心写业务逻辑,用这个编程时得来回在异步和同步之间切换,确实有点恶心,哈哈

J
jeffz#114 年前

不错不错,加油加油。不过好像测试的时候那段addEventListener有点没看懂是要干嘛的……还有addEventListener的那个回调函数是通过this访问的不是参数t,是不是文档哪里没有更新?

参与回复

登录后即可参与回复。登录