Callback 与 Promise 间的桥梁 —— promisify
作者:晃晃
本文原创,转载请注明作者及出处
Promise 自问世以来,得到了大量的应用,简直是 javascript 中的神器。它很好地解决了异步方法的回调地狱、提供了我们在异步方法中使用 return 的能力,并将 callback 的调用纳入了自己的管理,而不是交给异步函数后我们就无能为力了(经常有 callback 被莫名调用两次而导致程序出错)。
今天要介绍的是 Promisify,就是回调函数与 Promise 间的桥梁。
1. promisify 介绍
什么是 promisify 呢?顾名思义,就是“promise 化”,将一个不是promise的方法变成 promise 。举个例子:
// 原有的callback调用
fs.readFile('test.js', function(err, data) {
if (!err) {
console.log(data);
} else {
console.log(err);
}
});
// promisify后
var readFileAsync = promisify(fs.readFile);
readFileAsync('test.js').then(data => {
console.log(data);
}, err => {
console.log(err);
});
这两个方法效果上是等价的,但是从掌控性来说的话,我更喜欢后面的写法。
那么什么样的方法可以通过 promisify 变成 promise 呢?这里就需要介绍一个名词,nodeCallback。什么样的 callback 叫 nodeCallback ?
nodeCallback 有两个条件:1. 回调函数在主函数中的参数位置必须是最后一个;2. 回调函数参数中的第一个参数必须是 error 。举个例子:
- 回调函数在主函数中的参数位置
// 正确
function main(a, b, c, callback) {
}
// 错误
function main(callback, a, b, c) {
}
- 回调函数参数中的第一个参数必须是 error
// 正确
function callback(error, result1, result2) {
}
// 错误
function callback(result1, result2, error) {
}
这样,通过 nodeCallback ,我们定义了一个能被 promisify 的函数的格式,即,满足 nodeCallback 形式的方法,我们可以通过 promisify 来让它变成一个返回 promise 的方法。
2. promisify 的实现
下面我们来根据上述条件来手动实现一个 promisify 。
首先 promisify 需要返回一个 function ,并且这个 function 要返回一个 promise
var promisify = (func) => {
return function() {
var ctx = this;
return new Promise(resolve => {
return func.call(ctx, ...arguments);
})
}
}
其次,原 func 的最后一个参数是 callback
var promisify = (func) => {
return function() {
var ctx = this;
return new Promise(resolve => {
return func.call(ctx, ...arguments, function() {
resolve(arguments);
});
})
}
}
然后,回调函数中的第一个参数是 error 标记
var promisify = (func) => {
return function() {
var ctx = this;
return new Promise((resolve, reject) => {
return func.call(ctx, ...arguments, function() {
var args = Array.prototype.map.call(arguments, item => item);
var err = args.shift();
if (err) {
reject(err);
} else {
resolve(args);
}
});
})
}
}
最后,做一些优化,比如 this 作用域的自定义、回参只有一个时不返回数组
var promisify = (func, ctx) => {
// 返回一个新的function
return function() {
// 初始化this作用域
var ctx = ctx || this;
// 新方法返回的promise
return new Promise((resolve, reject) => {
// 调用原来的非promise方法func,绑定作用域,传参,以及callback(callback为func的最后一个参数)
func.call(ctx, ...arguments, function() {
// 将回调函数中的的第一个参数error单独取出
var args = Array.prototype.map.call(arguments, item => item);
var err = args.shift();
// 判断是否有error
if (err) {
reject(err)
} else {
// 没有error则将后续参数resolve出来
args = args.length > 1 ? args : args[0];
resolve(args);
}
});
})
};
};
测试
// nodeCallback方法func1
var func1 = function(a, b, c, callback) {
callback(null, a+b+c);
}
// promise化后的func2
var func2 = promisify(func1);
// 调用后输出6
func1(1, 2, 3, (err, reuslt) => {
if (!err) {
console.log(result); //输出6
}
})
func2(1, 2, 3).then(console.log); //输出6
以上便是 promisify 的介绍和实现,事实上有很多用 callback 来实现异步的第三方库提供的方法都是按照 nodeCallback 格式的,所以它们都可以通过 promisify 来让它变成 promise ,在遇到这些方法的时候就可以更灵活地使用啦。
iKcamp官网:http://www.ikcamp.com
访问官网更快阅读全部免费分享课程:《iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享》。
包含:文章、视频、源代码
iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。
【11月11号】上海iKcamp最新活动
与
“天天练口语”小程序总榜排名第四、教育类排名第一的研发团队,面对面沟通交流。
Callback 与 Promise 间的桥梁 —— promisify的更多相关文章
- 前端面试送命题(二)-callback,promise,generator,async-await
前言 本篇文章适合前端架构师,或者进阶的前端开发人员:我在面试vmware前端架构师的时候,被问到关于callback,promise,generator,async-await的问题. 首先我们回顾 ...
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- 原生JS中 callback,promise,generator,async-await 的简介
callback,promise,generator,async-await 的简介 javascript异步的发展历程. ES6 以前: 回调函数(callback):nodejs express ...
- callback、promise和async、await的使用方法
callback 回调是一个函数被作为一个参数传递到另一个函数里,在那个函数执行完后再执行.通俗的讲就是 B函数被作为参数传递到A函数里,在A函数执行完后再执行B. promise Promise 是 ...
- 《React-Native系列》3、RN与native交互之Callback、Promise
接着上一篇<React-Native系列>RN与native交互与数据传递,我们接下来研究另外的两种RN与Native交互的机制 一.Callback机制 首先Calllback是异步的, ...
- 【并发编程】Future模式添加Callback及Promise 模式
Future Future是Java5增加的类,它用来描述一个异步计算的结果.你可以使用 isDone 方法检查计算是否完成,或者使用 get 方法阻塞住调用线程,直到计算完成返回结果.你也可以使用 ...
- Web 前端 - 优雅地 Callback 转 Promise :aw
前言 当今 ES7 标准大行其道,使用 async + await 将异步逻辑同步书写已经普及,但是却有许多旧库或旧代码尚未完全 Promise 化,急需一个小工具去挖去这代码中藓疾. 设计和实现 由 ...
- callback转Promise
环境: nodejs - v6.2.0 const fs = require('fs'); let Promise = require('bluebird'); let readSync = fun ...
- Future、Callback、Promise
推荐下边两篇,写的很棒 https://juejin.im/post/5b126065e51d4506bd72b7cc https://www.cnkirito.moe/future-and-prom ...
随机推荐
- 接口测试入门(2)--get和post初级请求/使用httpclient做一个获取信息list的请求(需要登录才可以)
抛去测试自动化的架构来,直接写单个测试用例的思路如下: 1.获取测试case的接口,对每一个接口的请求方式(get/post/delete/put)进行分析,是否需要参数(不同的用例设置不同的参数,如 ...
- 如何用一天时间实现自己的RPC框架
前言 最近,闲来无事,自己写了一个简单的RPC框架,我把它叫做SimpleRpc.它有多简单?一共只有1400行代码.这个RPC只是作为自己试验作品,交流技术之用,当然如果你敢用,也可以放到生产环境之 ...
- 基于注解方式实现Aop
开启注解扫描 <context:component-scan base-package="aopSpring"></context:component-scan& ...
- C3P0 WARN: Establishing SSL connection without server's identity verification is not recommended
c3p0的出现,是为了大大提高应用程序和数据库之间访问效率的. 它的特性: 编码的简单易用 连接的复用 连接的管理 今天在配置C3p0的时候出现了这个warn 原因是因为要验证SSL Wed Se ...
- [转]Xcode的快捷键及代码格式化
Xcode比较常用的快捷键,特别是红色标注的,很常用.1. 文件CMD + N: 新文件CMD + SHIFT + N: 新项目CMD + O: 打开CMD + S: 保存CMD+OPt+S:保存所有 ...
- Linux入门之常用命令(7)压缩
compress filename 压缩 -d解压缩 *.Z bzip -d解压缩 -z压缩 *.bz2 bzcat filename .bz2 读取压缩文件内容 gzip -d解压缩 -#压 ...
- 支持向量机SVM(二)
[转载请注明出处]http://www.cnblogs.com/jerrylead 6 拉格朗日对偶(Lagrange duality) 先抛开上面的二次规划问题,先来看看存在等式约束的极值问题求法, ...
- JSP获取input(含正则表达式)
<%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> < ...
- Java面向对象 IO (四)
Java面向对象 IO (四) 知识概要: (1)打印流 (2)序列流 SequenceInputStream (3)ObjectInputStream与Ob ...
- Jquery实现鼠标移到某个对象,弹出显示层。
/** * 鼠标移上去显示层 * @param divId 显示的层ID * @returns */ $.fn.myHoverTip = function(divId) { var div = $(& ...