介绍

pify的功能和util.promisify一样,用来将一个函数包装为支持Promise的形式。

项目地址:https://github.com/sindresorhus/pify

源码分析

将原本不支持Promise调用的函数转化成Promise风格,最简单的方法可以这么写:

1
2
3
4
5
6
7
8
9
function promisify(f) {
return function () {
return new Promise((resolve, reject) => {
f.apply(this, [].slice.call(arguments).concat((err, val) => {
return err ? reject(err) : resolve(val)
}))
})
}
}

因为对于支持错误优先的回调函数,总是这种写法,例如:

1
2
3
4
5
6
7
fs.readFile('package.json', 'utf-8', (err, data) => {
if (err) {
// 处理错误
return
}
// 处理数据
})

回调函数总是作为最后一个参数,所以上面我们才可以:

1
2
3
[].slice.call(arguments).concat((err, val) => {
return err ? reject(err) : resolve(val)
})

Promise的处理逻辑追加到参数列表的末尾。

pify库的核心代码和上面基本相同,但提供了更多的处理。例如选项:exclude: [/.+(Sync|Stream)$/]排除了以SyncStream结尾的函数名,避免了我们错误的对函数使用promisify。

除了对函数名处理外,pify还提供对整个模块内的函数进行promisify:

1
2
3
4
for (const key in input) { // eslint-disable-line guard-for-in
const property = input[key];
ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property;
}

其中filter函数过滤掉符合特定模式的函数名,使用者可以在选项中配置。

另外,Node自带了util.promisify函数,我们不用手动去写,但是util.promisify不能对整个模块内的函数promisify