作者:晃晃

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

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. temp-成都农商行路径

    route add 30.3.4.0 mask 255.255.255.0 30.3.12.254 route add 30.3.12.0 mask 255.255.255.0 30.3.12.254 ...

  2. mysql数据库-初始化sql建库建表-关联查询投影问题

    下面是一个简易商城的几张表的创建方式 drop database if exists shop ; create database shop CHARACTER SET 'utf8' COLLATE ...

  3. 鸟哥Linux学习笔记07

    1, vi 是 老式的文字处理器,不过功能已经很齐全了,但是还是有可以进步的地方. vim可以说是程序开发者的一项很好用的工具,vim官网(http://www.vim.org)自己也说vim是一个“ ...

  4. sql server 把数据 复制成脚本文件

    问题描述:想把一个数据库里的表和字段复制到另一个数据库里: 方法一:a.生成脚本文件 选择数据库右键->任务->生成脚本: b. 选择特定的数据库对象->下一步: c.高级-> ...

  5. Unity GameObject Class

    GameObject  Note : gameObject 指的是当前挂着的对象. class in UnityEngine / Inherits from:Object     Descriptio ...

  6. Hive 存储类型 StoreType

    file_format: : SEQUENCEFILE | TEXTFILE -- (Default, depending on hive.default.fileformat configurati ...

  7. Delphi10.2 VCL Forms Application 的构成

    Delphi10.2 项目的构成(File Extensions of Files Generated by RAD Studio) Step1.打开 Delphi10.2,选择[File | New ...

  8. Manacher’s Algorithm (神啊)

    (转载自)http://blog.csdn.net/hopeztm/article/details/7932245 这里描述了一个叫Manacher’s Algorithm的算法. 算法首先将输入字符 ...

  9. Next Greater Element I

    You are given two arrays (without duplicates) nums1 and nums2 where nums1's elements are subset of n ...

  10. myeclipse的快捷键

    ------------------------------------MyEclipse 快捷键1(CTRL)-------------------------------------Ctrl+1 ...