热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Promise异步编程模式总结初始化Promise对象统一错误处理PromisifyfromCallbackMongoosePromisify

Promise是JavaScript中的一种异步编程范式,一个Promise对象表示一个即将完成但还未完成的操作。鉴于JavaScript中异步和回调的编程风格,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.all(iterable)iterable(比如数组)中所有Promise都resolve时,该Promise resolveiterable中任何一个被reject,则该Promise被reject
Promise.race(iterable)iterable中任意一个Promise被resolvereject,该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);

文章出处


推荐阅读
  • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
  • 开发笔记:读《分布式一致性原理》JAVA客户端API操作2
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了读《分布式一致性原理》JAVA客户端API操作2相关的知识,希望对你有一定的参考价值。创 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • node.jsurlsearchparamsAPI哎哎哎 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • java实现rstp格式转换使用ffmpeg实现linux命令第一步安装node.js和ffmpeg第二步搭建node.js启动websocket接收服务
    java实现rstp格式转换使用ffmpeg实现linux命令第一步安装node.js和ffmpeg第二步搭建node.js启动websocket接收服务第三步java实现 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • 1.移除consol.log()的babel插件安装:npmibabel-plugin-transform-remove-console-D配置:babel.config.js:这 ... [详细]
  • 技术周报·2021-05-07-小编推荐向现代Javascript转型原文标题:Publish,ship,andinstallmodernJavaScriptforfaste ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
author-avatar
sweeteenring
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有