zoukankan      html  css  js  c++  java
  • NodeJs回调操作Promise化

    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会增加一定的代码量,也有一定的学习曲线。

  • 相关阅读:
    第五讲:深入hibernate的三种状态
    mysql安装图解 mysql图文安装教程(详细说明)
    Codeforces 13C
    ubuntu常用软件
    git安装方法
    SSH免密码登录的方法
    bash 小技巧
    Haskell 学习
    客户端connect返回错误显示No route to host
    ubuntu下C操作Mysql数据库第一步
  • 原文地址:https://www.cnblogs.com/sunshine-anycall/p/5654115.html
Copyright © 2011-2022 走看看