NodeJs回调操作Promise化
2016-07-08 17:27
447 查看
mongoose是一个NodeJs下MongoDB的ORM库。使用这个库,您从DB到表(collection)都不用创建了。只需要在项目中定义好
Model。
下面就是用上一篇的代码来演示如何把mongoose的数据库操作里的回调地狱(callback hell)轻松化解掉。
上一篇Petshop的代码在这里。
打开Promise的开关
mongoose已经开启了对Promise的支持,只需要指定明确的Promise库就可以:
var mongoose = require('mongoose'), Promise = require('bluebird');
本来每一个model的定义都需要引入mongoose库,然后每次都给mongoose库指定Promise库太过冗繁。所以我们抽象代码,在models目录下创建一个base目录,然后在里面添加一个index.js文件:
//petshop/server/models/index.js
var mongoose = require('mongoose'), Promise = require('bluebird');
mongoose.Promise = Promise;
module.exports = mongoose;
然后在model的定义都是用export的添加Promise的mongoose:
var mongoose = require('./base'), bcrypt = require('bcrypt-nodejs'); var Schema = mongoose.Schema; var userSchema = new Schema({ username: {type: String, unique: true, required: true}, password: {type: String, required: true} }); ... module.exports = mongoose.model('User', userSchema);
这样,使用了base目录下的mongoose定义的model都具备了Promise的能力。
在调用查找更新等方法的时候只需要这样:
User.findOne({ username: username }).exec().then(function (u) { if (!u) { done(null, false); return; } var verifyPasswordAsync = Promise.promisify(u.verifyPassword, { context: u }); verifyPasswordAsync(password).then(function (match) { console.log('password match ' + match); if (!match) { console.log('is match ' + match); done(null, false); } else { done(null, u); } }); }).catch(function (err) { done(err); });
解释如下:
第一行代码
User.findOne({ username: username }).exec()在exec调用之后就返回了一个Promise。后面就可以使用Promise的then方法来开始Promise的方式依次调用和异常处理了。
单独promise化一个方法
在mongoose内置的Promise支持不能完成某些方法的时候还可以另外使用bluebird库来单独的针对这个方法来使其promise化。比如上例的u.verifyPassword代码:
userSchema.methods.verifyPassword = function (password, callback) { bcrypt.compare(password, this.password, function (err, match) { if (err) { return callback(err); } callback(null, match); }); };
单独的promise化
verifyPassword方法:
var verifyPasswordAsync = Promise.promisify(u.verifyPassword, { context: u });
之后的使用:
verifyPasswordAsync(password).then(function (match) { console.log('password match ' + match); if (!match) { console.log('is match ' + match); done(null, false); } else { done(null, u); } });
Promise化的一般原则
对于上面例子这里稍作引申。Promise化的时候使用的是bluebird库。
下面使用的例子代码如下:
function Dog(name) { this.name = !name ? 'Tiger': name; } Dog.prototype.bite = function(target, cb){ console.log(this.name + ' bite ' + target); cb(null, target); };
Promise化一个对象
Promise化一个对象使用promisifyAll方法。
var Promise = require('bluebird'); var d = Promise.promisifyAll(new Dog()); d.biteAsync('hellokitty');
输出:
Tiger bite hellokitty
注意:Promise化之后调用方法需要加上
Async后缀。
bite=>
biteAsync。
Promise化一个方法
Promise化的是一个带有回调的方法。这个Promise返回的结果就是回调正确的情况下获得的值。var someDog = new Dog("small"); var otherDog = new Dog("big"); var proDog = Promise.promisify(someDog.bite, {context: otherDog}); proDog('YOU').then(function(target) { console.log('then ' + target); walk(); })
在Promise话一个方法的时候需要考虑是不是指定context。上例中如果不指定context的时候会报错。一般,如果是require引入的库的方法不需要指定context,但是局部变量需要制定。指定context以后,方法的
this指向的上下文就是这个context对象。
总结
Promise化之后,回调地狱的问题就有很好的解决了。不过,还需要考虑项目的大小和回调的深度来决定是否要Promise化。毕竟Promise会增加一定的代码量,也有一定的学习曲线。相关文章推荐
- 使用ruby部署工具mina快速部署nodejs应用教程
- Google官方支持的NodeJS访问API,提供后台登录授权
- 浅谈Nodejs观察者模式
- nodejs教程之环境安装及运行
- nodejs中的fiber(纤程)库详解
- 基于NodeJS的前后端分离的思考与实践(五)多终端适配
- 基于NodeJS的前后端分离的思考与实践(二)模版探索
- 实例详解Nodejs 保存 payload 发送过来的文件
- 我的NodeJs学习小结(一)
- Node.js 应用跑得更快 10 个技巧
- nodejs中实现sleep功能实例
- Nodejs异步回调的优雅处理方法
- Windows系统下使用Sublime搭建nodejs环境
- nodejs实现获取某宝商品分类
- nodejs简单实现中英文翻译
- Node.js插件的正确编写方式
- 使用upstart把nodejs应用封装为系统服务实例
- NodeJS Web应用监听sock文件实例
- Nodejs学习笔记之测试驱动
- Nodejs学习笔记之Stream模块