文章目录
提出问题
在前端开发过程中,经常碰到以下情况:调用A方法获取B方法的参数a,调用B方法获取C方法的参数b,最终调用C服方法获取要在Web页面显示的真实数据,如下:
// 回调地狱
componentDidMount() {
getStudentInfo('zhangyun').then(studentInfo => {
console.log(studentInfo);
getClassInfo(studentInfo.classId).then(classInfo => {
console.log(classInfo);
getSchoolInfo(classInfo.schoolId).then(schoolInfo => {
console.log(schoolInfo);
this.setState({
schoolInfo,
})
})
})
})
}
上述代码通过如下步骤最终获取schoolInfo
信息:
- 调用
getStudentInfo
方法获取classId
,即getClassInfo
方法参数 - 调用
getClassInfo
方法获取schoolId
,即getSchoolInfo
方法参数 - 调用
getSchoolInfo
方法获取最终需要显示的schoolInfo
信息
当回调函数数量较少的时候还好处理,当数量越来越多,使用上面的方法会导致多层回调方法嵌套,也就是所谓的”回调地狱“,ES6提供了Promise
对象来避免以上情况的产生。
Promise简介
Promise
通俗来说就是1个对象,里面存放将来某个未来才会结束的事件(通常是1个异步操作的结果),分为Pending
(进行中)、Fulfilled
(已成功)和Rejected
(已失败)3种状态,Promise
对象的状态改变只有两种可能:
- 从
Pending
变成Fulfilled
- 从
Pending
变成Rejected
为了避免回调地狱,可以使用Promise
将异步操作以同步操作的流程表达出来。
Promise基本用法
创建1个Promise
实例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
// value表示异步操作的结果,返回value给Promise对象
resolve(value);
} else {
reject(error);
}
});
其中resolve
和reject
两个参数为JavaScript
提供的方法,其作用为:
- 改变
Promise
对象状态 - 传递结果:
resolved
或者rejected
Promise
实例生成后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数:
promise.then(function(value) {
// 参数1 success
}, function(error) {
// 参数2 failure
});
then
方法可以接受2个回调函数作为参数,其中:
- 参数1 <==>
resolved
回调函数 - 参数2 <==>
rejected
回调函数(可省略)
解决问题
Promise
解决回调地狱的方法就是将第1个回调函数返回的结果作为参数传入第2个回调函数。
话不多说,直接上代码:
import React, {
Fragment, PureComponent} from 'react';
import {
getStudentInfo,
getClassInfo,
getSchoolInfo
} from '@/services/es6Service'
class App extends PureComponent {
state = {
schoolInfo: {
schoolId: '',
schoolName: '',
city: ''
}
};
componentDidMount() {
// 避免回调地狱
this.asyncProcessStudent('zhangyun')
.then(this.asyncProcessClass)
.then(this.asyncProcessSchool)
.then(data => {
console.log(`第4步:输出schoolInfo`)
console.log(data);
})
}
// 创建第1个返回Promise对象的函数,9s后触发getStudentInfo方法
asyncProcessStudent = studentName => {
console.log(`第1步:输出studentName`)
return new Promise(resolve => {
// resolve(getStudentInfo(studentName));
setTimeout(() => resolve(getStudentInfo(studentName)), 9000);
})
}
// 创建第2个返回Promise对象的函数,4s后触发getClassInfo方法
asyncProcessClass = studentInfo => {
console.log(`第2步:输出studentInfo`)
return new Promise(resolve => {
// resolve(getClassInfo(studentInfo.classId));
setTimeout(() => resolve(getClassInfo(studentInfo.classId)), 4000);
})
}
// 创建第3个返回Promise对象的函数,1s后触发getSchoolInfo方法
asyncProcessSchool = classInfo => {
console.log(`第3步:输出classInfo`)
return new Promise(resolve => {
// resolve(getSchoolInfo(classInfo.schoolId));
setTimeout(() => resolve(getSchoolInfo(classInfo.schoolId)), 1000);
})
}
render() {
const {
schoolInfo} = this.state;
return (
<div>
<h1>使用Promise避免回调地狱</h1>
<div>
{
schoolInfo.schoolName}
</div>
</div>
);
}
}
export default App;
关键看如下代码:虽然asyncProcessStudent
触发时间是9s后,asyncProcessClass
和asyncProcessSchool
是4s和1s,但是由于asyncProcessStudent
的resolved
状态决定了then
中的方法,所以程序会同步执行。
this.asyncProcessStudent('zhangyun')
.then(this.asyncProcessClass)
.then(this.asyncProcessSchool)
.then(data => {
console.log(data);
})
输出结果如下: