博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
每天阅读一个 npm 模块(6)- pify
阅读量:7070 次
发布时间:2019-06-28

本文共 2939 字,大约阅读时间需要 9 分钟。

系列文章:

之前阅读的 npm 模块都来源于 这个项目,不过浏览了一些之后,发现好多都不太适合拿来做源码学习。如果读者有推荐的适合的模块,欢迎在评论区指出 ?

一句话介绍

今天阅读的模块是 ,通过它可以将很多采用 callback 方式进行调用的函数变成 Promise 调用,甚至采用 async/await 语法进行异步调用,从而可以在不修改调用函数的情况下避免回调地狱,也可以让代码具有更好的可读性,当前的版本是 4.0.0,周下载量约为 750 万。

用法

以 Node.js 中异步读取文件为例,常用的方法之一就是 fs.readFile(path, encoding, callback),这种通过回调函数进行异步操作的方式在以前的代码中十分常见 ,也是迫不得已。但是当如今拥有了 Promise 之后,这样写就显得十分麻烦,也不易于维护,所以可以通过 pify 这个模块将他们 Promise 化(即 Promisify)。

const fs = require('fs');const pify = require('pify');// 将 fs.readFile 变成 Promise 调用pify(fs.readFile)('package.json', 'utf8').then(data => {	console.log(JSON.parse(data).name);	// => 'pify'});// 通过 Promise 化函数,使用 async/await 语法(async function(){  const data = await pify(fs.readFile)('package.json', 'utf-8');  console.log(JSON.parse(data));  // => 'pify'})();复制代码

除了直接对一个函数进行 Promise 化外,还可以对一整个模块中的每一个函数进行 Promise 化:

const fs = require('fs');const pify = require('pify');// 将 fs 模块 Promise 化pify(fs).readFile('package.json', 'utf8').then(data => {	console.log(JSON.parse(data).name);	// => 'pify'});复制代码

源码学习

函数 Promise 化

// 源码 6-1module.exports = (input) => {    let ret;    if (typeof input === 'function') {    	ret = (...args) => processFn(input)(...args);    }    return ret;}复制代码

pify 主函数入口十分简单,如果传入的参数为函数,则经过 processFn 处理后作为结果返回,这里两个 ...args 虽然看起来一样,但实际上是 ES6新增的不同语法:

  • 第一个 ...args 用法叫做函数 rest 参数,可以用来获取函数的多余参数。它不同于 arguments 是一个类数组的类型,而是一个数组的实例:

    function foo(name, ...rest) {    console.log(rest, rest instanceof Array);}foo('Elvin', 'likes', 'JavaScript');// => [ 'likes', 'JavaScript' ], true复制代码
  • 第二个 ...args 的用法叫做扩展运算符(spread),类似于 rest 参数的逆运算,将一个数组进行展开:

    const x = [1, 2, 3];const y = [...x, 4];console.log(...x);// => 1 2 3console.log(y);// =>[ 1, 2, 3, 4 ]复制代码

这里实际上没有必要进行一层包裹,可以直接返回 processFn 处理的函数,即变成 ret = processFn(input),我也根据这个想法提出了 。

接下来看一看 processFn 这个函数的具体实现。这个函数也十分简单,主要做了四件事情:

  1. 构造一个 Promise 并将其作为函数的返回值。
  2. 构造一个 callback 函数,在这个函数中,假如有错误,则调用 Promise.reject() 方法抛出异常;假如无错误,则调用 Promise.resolve() 返回正常结果。
  3. 对于传入的参数 args 通过 push 方法追加我们刚刚构造的 callback 函数,从而形成完整的参数。
  4. 最后通过 fn.apply(this, args) 调用原函数。
// 源码 6-2const processFn = (fn) => function (...args) {    return new Promise((resolve, reject) => {       args.push((error, result) => {           if (error) {               reject(error);           } else {               resolve(result);           }       });        fn.apply(this, args);    });};复制代码

对象 Promise 化

对象的 Promise 化其实就是遍历对象的每一个属性,如果属性类型为函数的话,那么就用上节所说的 processFn 进行处理;如果属性类型不为函数的话,则直接返回:

// 源码 6-3module.exports = (input) => {    for (const key in input) {		const property = input[key];		ret[key] = typeof property === 'function' ? processFn(property) : property;	}}复制代码

写在最后

今天阅读的 模块的代码其实不难,但是它的的确确解决了开发过程中的痛点,所以它能在 上获得 1000+ 的赞,在 npm 上每周的下载量高达 750 万。

另外从 Node.js 8.0 起,就内置了 util.promisify(fn) 方法,可以实现部分 的功能,官方文档可以参考 ,关于两者的区别可以参考 ,主要为两点:

  1. pify 支持 Node.js 6.0 及以上版本, util.promisify(fn) 只支持 Node.js 8.0 及以上版本。
  2. pify 支持对整个模块 Promise 化, util.promisify(fn) 只支持对单个函数的 Promise 化。

关于我:毕业于华科,工作在腾讯, 欢迎来访 ^_^

转载地址:http://rqhll.baihongyu.com/

你可能感兴趣的文章
布尔类型
查看>>
MusicPlayer
查看>>
eclipes安装ADT错误处理
查看>>
Java 中的System.exit
查看>>
使用SVN钩子强制提交日志和限制提交文件类型
查看>>
AngularJS in Action读书笔记3——走近Services
查看>>
学习SpringMVC——你们要的REST风格的CRUD来了
查看>>
Java:输入输出流 java.io包的层次结构
查看>>
阿里云服务API的试用
查看>>
【MySQL 忘记密码】MySQL忘记密码怎么解决 mysql5.5 windows7
查看>>
JavaScript 的基础学习(一)
查看>>
360周鸿祎:你能不能像打游戏一样干工作?
查看>>
剑法三套,程序员也能赚大钱(3) 转
查看>>
Django 信号
查看>>
NLPIR数据语义挖掘技术为企业提供精准管理
查看>>
[Istio]Kubernetes集群部署Istio 1.0
查看>>
HTML5篇
查看>>
分页技术之PageDataSource类
查看>>
How to: Create Instances of ASP.NET User Controls Programmatically
查看>>
关于 python中的 TKinterlistbox 控件加横竖滚动条
查看>>