百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>JS教程> js Promise异步编程示例
分享文章到:

js Promise异步编程示例

发布时间:01/15 来源: 浏览: 关键词:
Promise的诞生与Javascript中异步编程息息相关,js中异步编程主要指的是setTimout/setInterval、DOM事件机制、ajax,通过传入回调函数实现控制反转,下面我们来看js Promise异步编程示例.

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对象 padmin 拥有两个主要方法:

 

上述两个方法均返回一个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);

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有3人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板