早期的异步函数,由于还没有 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')
})
如何实现?
核心思想: 你要是能用
Promise
的resovle
函数替代原异步函数的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
函数有一个局限. 被包装的异步函数,回调函数必须是最后一个参数!