Promissify
# 前言
注意一下:源码这里有个小坑要注意一下,就是源码目录不能有中文路径,不然会报错。
# promisify函数是把 callback 形式转成 promise 形式
# promisify方法的实现
其中:
Reflect.apply(original, this, args)使用apply或者Reflect.apply的目的是为了保存this对象。- promisify函数主要针对了采用遵循常见的错误优先的回调风格的函数(也就是将
(err, value) => ...回调作为最后一个参数),并返回一个返回 promise 的版本。 - 其中通过
reject返回函数中的错误reject(err),使用的resolve()返回回调函数。这样就可以通过promise.catch()来捕捉函数中的错误异常,并且通过promise.then()或者await等方法获取回调函数进行链式调用。
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);
// original(...args)
});
}
return fn;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用Reflect.apply(original, this, args);的原因
保存this的对象,防止丢失。也可使用apply等方法将函数中的this保存下来。如果不使用此方法,会造成promise化中函数的this丢失。
例如:
class Foo {
constructor() {
this.a = 42;
}
bar(callback) {
callback(null, this.a);
console.log('bar', this)
}
}
const foo = new Foo();
foo.bar(()=>{})// 1
const naiveBar = promisify(foo.bar);
naiveBar().then(a => {}) // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面代码中,如果没有使用apply等方法去对this进行一个保存。1中会正常输出Foo类中的属性a = 42;但是2中会爆出如下错误:

通过代码调试的方法可以看到,第一次调用没有promisify化的函数bar的时候this是正常的指向类的

而再次向下进行时,此时的bar函数已经被promisify化了。此时promisify函数没有做出this的保存,只是对函数参数进行了简单的结构传参:

则this丢失,变成了undefined,所以报错了。

而对函数的this对象进行一次this的传入,函数中会丢失类中的this,而this指向了promisify函数通过apply方法传入的this,在这里是window对象,所以这里也证明了==this总是在运行中获取确认指向的,而不是在一开始就定了的==


# 总结
本次源码阅读中,除了跟着川哥学习了promisify函数的实现以及应用场景,还对函数中Reflect.apply(original, this, args)进行了一次深入的了解,从而学到了一部分this的运行方法以及指向的问题。
上两周被大作业折磨的没空写下笔记,如今终于空了下来对这次的笔记进行了梳理和解析。希望能够对未来看到这篇笔记的朋友们有所帮助。
谢谢川哥,谢谢各位帮助过
编辑 (opens new window)
上次更新: 2022/02/21, 05:57:00