Node中的util.promisify()方法的基本使用和实现
作者:爆燃的小牛
异步编程解决方案
我们知道,在JS
中实现异步编程主要是通过以下几种方案:
- 回调函数:也是在
ES6
之前用的最多的方式,缺点是容易造成callback hell
,可读性很差 - 观察者模式:在
NodeJS
中的很多模块都继承了EventEmitter
模块,NodeJS
所有的异步I/O
操作在完成时都会发送一个事件到事件队列。所有这些产生事件的对象都是events.EventEmitter
的实例。 Generator
:ES6 新引入了 Generator 函数,可以通过yield
关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。Promise
方案:号称是异步编程的终极解决方案async / await
:async
是ES7引入的语法 ,也是属于Promise
方案中的一种
今天就聊一下在node
中的一个util.promisify()
这个API
的基本使用和基本实现。
promisify
promisify
这个方法可以是一个高阶函数,接受一个函数作为入参,可以将原本考回调函数实现的异步编程转化为promis
的方案。这也是node提供出来,可以将之前非promise
的方法通过这个api
转化成promise
来处理
基本使用
以一个简单的读写文件的fs.readFile
和readFileSync
为例说明。我们知道fs.readFile
是通过回调函数的方式来获取读到的文件内容。而fs.readFileSync
是通过同步的方式读取到文件内容。我们就可以使用promisify
这个函数,将fs.readFile
转变成promise
的方式
// const.js 被读取的文件 const str = 123
// index.js const fs = require('fs') const path = require('path') const { promisify } = require('util') // 同步的方式读取const.js const data = fs.readFileSync(path.resolve(__dirname, './const.js')) console.log('readFileSync:', data.toString()); // 通过回调函数的方式获取const.js内容 fs.readFile(path.resolve(__dirname, './const.js'), (error, data) => { if (error) console.log('error', error); console.log('readFile', data.toString()); }) // 将fs.readFile转为promise的方式获取文件内容 const readFile = promisify(fs.readFile) readFile(path.resolve(__dirname, './const.js')) .then(data => { console.log('promisify: ', data.toString()) })
达到的效果也符合预期:
自己实现一个promisify
我们在这里也自己实现一个promisify
函数,达到上面的效果。即将一个接受回调函数通过回调完成异步编程的方式改为promise
的方式
我们分析分析,思路其实很简单, 原本的函数接受一系列的参数,最后一个参数是一个回调函数,一般在node
中错误先行,最后一个参数即任务完成时的回调函数也接受两个参数一个是error
一个是处理后得到最后结果的data
。如果有error
的话就reject
没有就resolve
返回promise
结果即可,详细分析步骤如下:
- 我们实现的
xpromisify
是一个高阶函数,即接受一个函数作为参数 - 接受的这个函数也有可能接受参数,所以我们对这个函数进行升阶处理,才能让这个函数接受其他参数
- 我们最后返回的一定是一个
Promise
实例 - 我们可以将
步骤2
中这个函数接受的参数数组得到(比如上述例子中fs.readFile()
函数接受的path.resolve(__dirname, './const.js')
),再构造一个函数作为回调函数,作为完整的参数,使用apply
的方式让在步骤一
中接受的函数执行 - 构造的回调函数中判断步函数完成是否有错误,如果有错误我们
reject
掉,如果没有错误的话就把这个data
给resolve
即可
完整的代码实现如下所示:
// x-promisify.js // xPromisify 是一个高阶函数,会将接受的fn函数转为promise const xPromisify = (fn) => { // 接受的fn函数也会接受其他参数,所以升阶处理,return 一个函数这样就可以接受其他参数了 return wrapFn = (...args) => { // 最终返回的肯定是一个promise实例 return new Promise((resolve, reject) => { // 接受参数中加一个回调函数reject/resolve 最后结果 args.push((error, data) => { if (error) reject(error) resolve(data) }) // 此时args参数中就包含的fn执行所需要的所有参数了 fn.apply(null, args) }) } } module.exports = { xPromisify }
我们可以通过上述例子的fs.readFile
这个函数来检查一下:
const { xPromisify } = require('./x-promisify') const xReadFile = xPromisify(fs.readFile); xReadFile(path.resolve(__dirname, './const.js')) .then(data => { console.log('data', data.toString()) })
执行效果如下所示:
总结
其实我们做的事情只是将回调函数的逻辑做了修改,原本是直接在回调中处理业务逻辑,这里我们修改为在回调函数中把异步事件处理的结果通过reject / resove
给返回出去 我们也可以看一下在NodeJS
中对这一部分的实现:
到此这篇关于Node中的的util.promisify()方法的基本使用和实现的文章就介绍到这了,更多相关Node 的util.promisify()方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!