作者:晃晃

本文原创,转载请注明作者及出处

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 。举个例子:

  1. 回调函数在主函数中的参数位置
// 正确
function main(a, b, c, callback) { } // 错误
function main(callback, a, b, c) { }
  1. 回调函数参数中的第一个参数必须是 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最新活动

报名地址:http://www.huodongxing.com/event/5409924174200

“天天练口语”小程序总榜排名第四、教育类排名第一的研发团队,面对面沟通交流。

Callback 与 Promise 间的桥梁 —— promisify的更多相关文章

  1. 前端面试送命题(二)-callback,promise,generator,async-await

    前言 本篇文章适合前端架构师,或者进阶的前端开发人员:我在面试vmware前端架构师的时候,被问到关于callback,promise,generator,async-await的问题. 首先我们回顾 ...

  2. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  3. 原生JS中 callback,promise,generator,async-await 的简介

    callback,promise,generator,async-await 的简介 javascript异步的发展历程. ES6 以前: 回调函数(callback):nodejs express ...

  4. callback、promise和async、await的使用方法

    callback 回调是一个函数被作为一个参数传递到另一个函数里,在那个函数执行完后再执行.通俗的讲就是 B函数被作为参数传递到A函数里,在A函数执行完后再执行B. promise Promise 是 ...

  5. 《React-Native系列》3、RN与native交互之Callback、Promise

    接着上一篇<React-Native系列>RN与native交互与数据传递,我们接下来研究另外的两种RN与Native交互的机制 一.Callback机制 首先Calllback是异步的, ...

  6. 【并发编程】Future模式添加Callback及Promise 模式

    Future Future是Java5增加的类,它用来描述一个异步计算的结果.你可以使用 isDone 方法检查计算是否完成,或者使用 get 方法阻塞住调用线程,直到计算完成返回结果.你也可以使用  ...

  7. Web 前端 - 优雅地 Callback 转 Promise :aw

    前言 当今 ES7 标准大行其道,使用 async + await 将异步逻辑同步书写已经普及,但是却有许多旧库或旧代码尚未完全 Promise 化,急需一个小工具去挖去这代码中藓疾. 设计和实现 由 ...

  8. callback转Promise

    环境:  nodejs - v6.2.0 const fs = require('fs'); let Promise = require('bluebird'); let readSync = fun ...

  9. Future、Callback、Promise

    推荐下边两篇,写的很棒 https://juejin.im/post/5b126065e51d4506bd72b7cc https://www.cnkirito.moe/future-and-prom ...

随机推荐

  1. 如何手动获取Spring容器中的bean(ApplicationContextAware 接口)

    ApplicationContextAware 接口的作用 先来看下Spring API 中对于 ApplicationContextAware 这个接口的描述:   即是说,当一个类实现了这个接口之 ...

  2. overflow使用說明

    必須設置的CSS屬性: { display:block; //或者inline-block,text-overflow:ellipsis只對block或者inline-block有效 white-sp ...

  3. JVM菜鸟进阶高手之路四

    转载请注明原创出处,谢谢! 由于很多的jvm分析最好是基于gc日志的,所以添加参数如下即可: -verbose:gc -XX:+HeapDumpOnOutOfMemoryError -XX:+Prin ...

  4. 自学Unity3D 之 贪吃蛇 添加摄像机跟随

    在Unity的世界中, 物体的位置都是由向量构成的. 今天所需要做的就是让摄像机保持跟蛇头的相对距离. 首先  设蛇头的位置在A 点  , 摄像机的位置在B 点 则  我们可以知道  他们的offse ...

  5. 最详细的cookie和浏览隐私之间的关系

    本文所说的"cookie",指的是浏览器相关的 cookie(也叫"HTTP cookie"). 浏览器 cookie 的主要功能是:帮助网站保存一些小片段的信 ...

  6. 【Kafka】操作命令

    生产者 ./kafka-console-producer.sh --broker-list --topic norm 消费者 ./kafka-console-consumer.sh --zookeep ...

  7. Sum It Up 广搜

    Sum It Up Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit St ...

  8. hdu4027 开方,记录

    A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use ...

  9. 初识Hibernate之关联映射(一)

    上篇文章我们对持久化对象进行的学习,了解了它的三种不同的状态并通过它完成对数据库的映射操作.但这都是基于单张表的操作,如果两张或者两张以上的表之间存在某种关联,我们又该如何利用持久化对象进行操作呢?本 ...

  10. Angular学习笔记(一)

    本文为原创文章,转载请标明出处 目录 架构 模块 组件 模板 元数据 数据绑定 指令 服务 依赖注入 模板与数据绑定 1. 架构 模块 Angular 应用是模块化的,并且 Angular 有自己的模 ...