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

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处!


















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/5654115.html ,如需转载请自行联系原作者
相关文章
|
存储 JavaScript 前端开发
vue3 专用 indexedDB 封装库,基于Promise告别回调地狱(二)
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API 这个大概是官网吧,原始是英文的,现在陆续是出中文版。有空的话还是多看看官网。
|
1月前
|
前端开发 JavaScript
js开发:请解释Promise是什么,以及它如何解决回调地狱(callback hell)问题。
Promise是JavaScript解决异步操作回调地狱的工具,代表未来可能完成的值。传统的回调函数嵌套导致代码难以维护,而Promise通过链式调用`.then()`和`.catch()`使异步流程清晰扁平。每个异步操作封装为Promise,成功时`.then()`传递结果,出错时`.catch()`捕获异常。ES6的`async/await`进一步简化Promise的使用,使异步代码更接近同步风格。
18 1
|
4月前
|
前端开发 JavaScript
用原生JavaScript(ES5)来实现Promise的等效功能(异步回调)
用原生JavaScript(ES5)来实现Promise的等效功能(异步回调)
|
11月前
|
前端开发 小程序 Java
小程序不同页面的异步回调,callback和promise的使用讲解
小程序不同页面的异步回调,callback和promise的使用讲解
145 0
|
前端开发
【Promise】一文带你了解promise并解决回调地狱
【Promise】一文带你了解promise并解决回调地狱
91 0
|
前端开发
8、同步与异步(回调、Promise、async函数)
8、同步与异步(回调、Promise、async函数)
101 0
|
前端开发
手写promise自定义封装异步任务回调的执行
手写promise自定义封装异步任务回调的执行
|
前端开发
一个Promise指定多个成功或者失败的回调详解
一个Promise指定多个成功或者失败的回调详解
|
存储 缓存 JavaScript
vue3 专用 indexedDB 封装库,基于Promise告别回调地狱
IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 可以使用索引实现对数据的高性能搜索。
436 0
vue3 专用 indexedDB 封装库,基于Promise告别回调地狱