前言
本期的课程主要学习面试高频考点 promisify 的原理和实现。
- 源码位置:node/util.js at main · nodejs/node (github.com)
promisify
promisify 是Node.js 内置的 util
模块中的一个函数,该方法将基于回调的函数转换为基于 Promise 的函数。这使您可以将 Promise 链和 async/await
与基于回调的 API 结合使用。
常规的回调方式
例如使用node的fs模块读取文件时:
const fs = require('fs')
fs.readFile('./package.json', function callback(err, buf) {
const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name)
})
通常只有一个回调函数的时候还好,当回调函数中又包含了回调函数的时候,你的代码将拥有无数的花括号,也就是所谓的回调地狱,光是听名字就很可怕了。
util.promisify()
的出现将很好的解决这些问题。
使用util.promisify()
将 fs.readFile()
的回调函数转换为返回 Promise 函数:
const fs = require('fs')
const util = require('util')
// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = util.promisify(fs.readFile)
// 现在可以将 readFile() 与 await 一起使用!
const buf = await readFile('./package.json')
const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name)
promisify 的工作原理
promisify 的简单实现,详情参考:若川的文章
function promisify(original){
function fn(...args){
return new Promise((resolve, reject) => {
args.push((err, ...values) => {
if(err){
return reject(err);
}
resolve(values);
});
// original.apply(this, args);
Reflect.apply(original, this, args);
});
}
return fn;
}
const fs = require('fs')
// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = promisify(fs.readFile)
// 现在可以将 readFile() 与 await 一起使用!
const buf = await readFile('./package.json')
const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name) // 'Example'
promisify 方法接收一个回调函数作为参数,返回一个新的函数,这个函数将多绑定两个参数,一个是this,另一个是Promise 对象的结果,成功返回回调函数执行的结果,失败返回错误信息。
总结
使用 promisify 包装后,可以通过 Promise 的链式调用或者使用await获取回调的内容,使你的代码更加简洁优雅。结尾再复习一下node模块es6 调用的方式,如下:
import util from 'node:util'