如何用 Promise 解决回调地狱
这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。
导语
上文了解什么是回调地狱,如何使用thunk
函数解决回调地狱,具体可参考上文: JS 如何用 thunk 函数解决回调地狱?。解决回调地狱的方法有很多,本文讨论如何使用 Promise
来解决回调地狱。
写一个回调地狱
const fn = (str, callback) => {
setTimeout(() => {
console.log(str)
callback(str)
}, 100);
}
fn('1', () => {
fn('2', () => {
fn('3', () => {
fn('4', () => {
console.log('done')
})
})
})
})
这里的 fn
调用形成了一个喜闻乐见的回调地狱。运行结果:
1
2
3
4
done
目的是在异步函数fn
中,依次传递参数 1-4,并且依次去执行。
构造 Promise 工厂函数
const promiseFactory = (str) => {
return new Promise((resolve) => {
fn(str, resolve)
})
}
原理很简单,主要目的就是将 参数和回调进行分离,这也是解决回调地狱的基本原则。通过 promise 工厂函数,接受除了 callback
意外的所有参数,然后利用 promise 的 resolve 替代原有的 callback
去调用原函数。这样就完成了一个 promise 工厂函数。
链式调用工厂函数
promiseFactory('1')
.then(() => promiseFactory('2'))
.then(() => promiseFactory('3'))
.then(() => promiseFactory('4'))
.then(() => { console.log('done') })
运行结果:
1
2
3
4
done
和原回调地狱方式调用的结果是完全一致的,实际上他们的执行顺序也是一致的
完整代码
const fn = (str, callback) => {
setTimeout(() => {
console.log(str)
callback(str)
}, 100);
}
// fn('1', () => {
// fn('2', () => {
// fn('3', () => {
// fn('4', () => {
// console.log('done')
// })
// })
// })
// })
const promiseFactory = (str) => {
return new Promise((resolve) => {
fn(str, resolve)
})
}
promiseFactory('1')
.then(() => promiseFactory('2'))
.then(() => promiseFactory('3'))
.then(() => promiseFactory('4'))
.then(() => { console.log('done') })
多参数的回调地狱
const fn = (greeting, myName, callback) => {
setTimeout(() => {
console.log(greeting + ',' + myName)
callback()
}, 100);
}
// fn('1', () => {
// fn('2', () => {
// fn('3', () => {
// fn('4', () => {
// console.log('done')
// })
// })
// })
// })
const promiseFactory = (greeting, myName) => {
return new Promise((resolve) => {
fn(greeting, myName, resolve)
})
}
promiseFactory('hehe', 'ouda')
.then(() => promiseFactory('hello', 'ouda1'))
.then(() => promiseFactory('hi', 'ouda2'))
.then(() => promiseFactory('haha', 'ouda3'))
.then(() => { console.log('done') })
运行结果:
hehe,ouda
hello,ouda1
hi,ouda2
haha,ouda3
done
在多参数的环境下同样适用,原则就是将 callback
以外的函数重新封装成工厂函数,然后将 promise 的 resolve 替代 callback
即可。
最终我们成功地可以将原来的嵌套回调,修改为了链式调用,这也是在我们开发中经常会用到的解决回调地狱的一个惯用手段。