如何实现一个 promisify ?

早期的异步函数,由于还没有 Promise,所以都是以回调的方式来处理异步任务的.

function someAsyncTask (num, cb) {
  setTimeout(() => {
    const result = num * 100
    typeof cb === 'function' && cb(result)
  }, 2000);
}

someAsyncTask(100, (result) => {
  console.log('回调异步处理的结果是:' + result)
})

目标和希望

function promisify (asyncFn) {
    // 如果实现一个逻辑,将 asyncFn 转换成一个 Promise 对象返回?
    return  new Promise () //....
}

const promiseInstance = promisify(someAsyncTask)

promiseInstance.then(data=>{
    console.log('在这里拿到异步返回的数据 data')
})


如何实现?

核心思想: 你要是能用 Promiseresovle 函数替代原异步函数的 cb 函数即可.

function someAsyncTask (num, cb) {
  setTimeout(() => {
    const result = num * 100
    typeof cb === 'function' && cb(result)
  }, 2000);
}

// 接受一个异步任务函数(非 promise)
// 返回一个 promise 对象
function promisify (asyncTask) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      // 用你的 resolve 去覆盖别人本身的 cb 即可.
      asyncTask.apply(null, [...args, resolve])
    })
  }
}

const p = promisify(someAsyncTask)
p(100).then(res => {
  console.log(res);
})

2s 后输出 10000

结果

完善一下这个例子.

上述例子,仅支持 Promise 的成功回调. 但是对于失败的 reject 却无法处理.

解决办法:

callback 具体指向 resolve 还是 reject 由当前的异步函数自己决定

function promisify (asyncTask) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      // 让用户自己决定调用 resolve 还是 reject
      let callback = (err) => {
        return err ? resolve : reject
      }
      asyncTask.apply(null, [...args, callback])
    })
}

注意: promisify 函数有一个局限. 被包装的异步函数,回调函数必须是最后一个参数!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容