如何实现一个 promisify ?

2022-01-21  本文已影响0人  人话博客

早期的异步函数,由于还没有 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 函数有一个局限. 被包装的异步函数,回调函数必须是最后一个参数!

上一篇下一篇

猜你喜欢

热点阅读