一,前言
上一篇,实现了 Promise 的两个静态 API:Promise.allSettled
和 Promise.any
,主要涉及以下几个点:
- 测试原生 Promise.allSettled 的使用;
- Promise.allSettled 的功能与特性分析;
- Promise.allSettled 的源码实现、执行分析、功能测试;
- 测试原生 Promise.any 的使用;
- Promise.any 的功能与特性分析;
- Promise.any 的源码实现、执行分析、功能测试;
本篇,实现一个 promisify 功能的工具函数;
二,promisify 介绍
1,什么是 promisify
promisify
功能:如字面意思“promise 化”
用于将异步回调 callback 形式的操作或 API 转换为 promise 形式;
2,promisify 的应用场景
目前主要用于 nodejs、小程序等场景
这些框架提供的 API 多为异步回调方式,比较容易形成编码中的“回调地狱”问题;
示例:nodejs 异步读取文件
const fs = require('fs') // 文件操作
fs.readFile('test', 'utf8', function(err, data){
if(err) reject(err) // 错误优先原则
fs.readFile(data, 'utf8', function(err, data){
if(err) reject(err)
console.log(data);
// ...
})
})
在 nodejs 提供的 util 工具包中也存在一个 promisify 函数:
const fs = require('fs')
const util = require('util')
// 将原本 callback 形式的异步API readFile -> promise 化
let readFile = util.promisify(fs.readFile);
readFile('test', 'utf8').then((data)=>{
return readFile(data, 'utf8');
}).then((data)=>{
console.log(data);
}).catch(err =>{// ...})
还提供了批量 promisify 操作:
let fs = require('fs');
promisifyAll(fs); // 对 fs 库导出的对象整体 promisify;
fs.readFileAsync('test', 'utf8').then(data=>{
console.log(data);
});
备注:promisifyAll 对库导出的对象整体 promisify 操作后,新的方法命名规则一般为:原方法名+"Async"
;
避免了异步回调导致的多层嵌套问题,提升了代码的可读性;
下面就一起实现一个 promisify;
三,promisify 实现
- 实现单一函数的 promise 化:
function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
}
这样,fn 就被进行了一次包装:将 callback 回调方式转为 promise 形式;
- 批量 promise 化:
function promisifyAll(obj) {
// 将对象转为数组,遍历数组中的fn,依次完成 promisify 操作
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'function') {
obj[key + 'Async'] = promisify(obj[key])
}
})
}
备注:目前很多框架和库的 API 都有对 promise 的支持,所以使用时可以查阅文档,如果实在没有,可以使用以上 promisify 函数进行转化;如:可以使用 bluebird.js
四,结尾
本篇,实现一个 promisify 工具函数,主要涉及以下几个点:
- promisify 简介和测试;
- promisify 功能的实现:promisify、promisifyAll;
下一篇,介绍 generator 生成器;