html form callback,Promise异步编程模式总结初始化Promise对象统一错误处理PromisifyfromCallbackMongoose Promisify...

Promise是JavaScript中的一种异步编程范式, 一个Promise对象表示一个即将完成但还未完成的操作。 鉴于JavaScript中异步和回调的编程风格, Promise模式可以有效地避免『Callback Hell』。

Promise 最初有q和bluebird等实现,在ES2015(ES6)提出后Promise已经进入标准,Node.js已经开始支持ES6的很多特性,包括Promise。

初始化

传入一个回调函数即可初始化一个Promise对象padmin:

var padmin = new Promise(function(resolve, reject){

user.find({role: 'admin'}, function(err, admins){

if(err) reject(err);

else resolve(admins);

});

});

除此之外,ES6还给出4种常用的初始化方式,下列方法均返回一个Promise对象:

方法

说明

Promise.all(iterable)

当iterable(比如数组)中所有Promise都resolve时,该Promise resolve;iterable中任何一个被reject,则该Promise被reject

Promise.race(iterable)

当iterable中任意一个Promise被resolve或reject,该Promise都会相应地结束

Promise.reject(err)

直接返回一个被reject的Promise对象

Promise.reject(value)

直接返回一个被resolve的Promise对象

Promise对象

Promise对象padmin拥有两个主要方法:

方法

说明

Promise.prototype.catch(onRejected)

当一个Promise被reject时调用onRejected

Promise.prototype.then(onFulfilled, onRejected)

当一个Promise被resolve时调用onFulfilled,被reject时调用onRejected

上述两个方法均返回一个Promise,这意味着.then和.catch可以链式书写。例如:

padmin

.then(function(admins){

doSthWith(admins);

})

.catch(function(err){

console.error(err);

});

统一错误处理

在任何一个then()回调中抛出的错误都会被后面的catch()所截获,以此可以做统一的错误处理:

padmin

.then(function(admins){

if(admins === null) throw new Error('query admin error');

return admins.length;

})

.then(function(length){

if(length === 0) throw new Error('empty admin list');

console.log(length + ' admins in total.');

})

.catch(function(err){

console.error(err);

});

Promisify

Node.js的内置库以及大量的NPM工具都采用『Error-First Callback』风格,例如:

fs.readFile('foo.txt', function(err, content){

if(err) console.error(err);

else console.log(content);

});

在Promise风格的代码中,通常会需要readFile返回一个Promise对象,于是常常会这样包装该API:

var readFileAsync = function(path){

return new Promise(function(resolve, reject){

fs.readFile(path, function(err, content){

if(err) reject(err);

else resolve(content);

});

});

}

readFileAsync('foo.txt')

.then(function(content){

console.log(content):

})

.catch(function(err){

console.error(err);

});

然而我们需要包装fs模块下的所有API 🙁 bluebird为此提供了有用的方法promisifyAll():

var fs = require("fs");

// 为fs的所有方法创建一个Promise包装,命名为xxxAsync

Promise.promisifyAll(fs);

fs.readFileAsync("foo.txt").then(...).catch(...);

当然也可以只包装一个函数:

var readFile = Promise.promisify(require("fs").readFile);

readFile("foo.txt").then(...).catch(...);

fromCallback

现在我们有了.promisify来把一个『Error-First Callback』风格的API包装为Promise风格。 在某些特定情形下,可能每次使用都需要先进行promisify,比如使用后即被销毁的临时对象。 例如从HTTP请求构造的req对象每次请求都是新的:

function(req, res, next){

User.find({name: req.body.name})

.then(function(user) {

var login = Promise.promisify(req.login);

return login.call(req, user);

})

.catch(next);

}

这时可以用Promise.fromCallback方法,直接由『Error-First Callback』调用生成Promise对象,而不需要生成Promise风格的方法。

function(req, res, next){

User.find({name: req.body.name})

.then(function(user) {

return BPromise.fromCallback(cb => req.login(user, cb));

})

.catch(next);

}

Mongoose Promisify

mongoose是MongoDB在JavaScript下的适配器(类似ORM),提供了模型验证、数据转换、业务逻辑钩子、查询钩子等对象建模工具。 mongoose有些API(如.exec())会返回内置的Promise,我们可以用一个更强的Promise来替代它:

var BPromise = require('bluebird');

mongoose.Promise = BPromise;

除exec(), execPopulate()系列函数外,mongoose多数API都是回调风格的,通常需要用Bluebird将其Promisify。 这些Mongoose API主要包括下列三类:

Model. Eg: User.findAsync(), User.findByIdAsync(), User.removeAsync(), User.updateAsync()

Model.prototype. Eg: user.saveAsync(), user.removeAsync()

Query.prototype. Eg: User.find().sortAsync(), User.find().populateAsync()

BPromise.promisifyAll(mongoose.Model);

BPromise.promisifyAll(mongoose.Model.prototype);

BPromise.promisifyAll(mongoose.Query.prototype);

这些Promise化的代码最好在代码载入时执行,但不要早于mongoose插件。否则这些插件就不会被Promise化了。

Promise化之后的mongoose用起来是这样的:

var UserSchema = mongoose.Schema({

name: String,

phone: String

});

var User = mongoose.model('User', UserSchema);

User.findAsync()

.then(users => console.log(users));

.catch(e => console.error(e));

某些mongoose插件可能需要在Promisify脚本之后执行较为方便。这时我们需要将受影响的模型再次Promise化:

var UserSchema = mongoose.Schema({...});

UserSchema.plugin(require('passport-local-mongoose'), {

usernameField: 'phone'

});

var User = mongoose.model('User', UserSchema);

BPromise.promisifyAll(User);

文章出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值