源码阅读05- promisify

85 阅读2分钟

我正在参与掘金会员专属活动-源码共读第一期,点击参与

普通转化 callback

callback 回调地狱,应该很多人都有经历过。应该有很多项目都会以 callback 的方式实现异步的过程。但我们肯定会遇到这样的场景:使用某个类库时发现提供的还是 callback 方式,而你项目早就迭代优化为 promise 或者是 async/await 的方式。

所以,promisify 函数就有其存在意义。其能够把 callback 形式转成 promise 形式。在之前,可能都会像我一样自己手动实现将 callback 转成 promise。

function convertPromise(id) {
	return new Promise((resolve,reject)=>{
    getUser(id,(err, result)=>{
      if(err) { reject(err)}
      resolve(err)
    })
  })
}

function getUser(id, function(err, result){
  if (err){return;}
  console.log(true)
})

promisify 转化 callback

promisify 就是实现了支持所有 callback 形式的转化,封装了一个通用的函数,使用简单方便。简单一行代码实现了上面8行代码的功能。

const getUserPromise = promisify(getUser);
const result = await getUserPromise(id);

源码分析

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;
}

从上面的源码可以看到 promisify 函数详细实现的过程:

  • 参数是原函数,返回结果时一个封装后的函数。所以在使用 promisify 函数后返回得到的是一个新的函数。
  • 新函数 fn 返回结果就是个 promise 。调用它时参数就是原函数的参数,并在原参数后增加了一个回调函数
  • 回调函数的第一个参数是 err 错误信息,第二个是 promise 返回值

Reflect.apply

其中 Reflect.apply(original, this, args) 它是什么?

MDN 上的解释是:静态方法 Reflect.apply() 通过指定的参数列表发起对目标(target)函数的调用。

Reflect . apply ****接收三个参数:

  • target :要调用的目标函数
  • thisArgument:target函数调用时绑定的this对象
  • ArgumentsList ****:它是一个类似数组的对象,用于指定应调用目标的参数。

返回值是目标函数的执行结果。

所以,Reflect.apply 其实就是一个函数的绑定并执行函数的过程,操作就和 Function.prototype.apply.call(func, thisArg, args)一样的。