遭遇“惡魔金字塔”
項目需要,封裝了一個省市區(qū)的地址選擇器組件。
可以根據(jù)省份id、城市id和區(qū)id對組件設置默認值。邏輯是這樣的:
- 獲取省份列表,選中默認省份;
- 第一步成功后,根據(jù)默認省份id獲取城市列表,選中默認城市;
- 第二部成功后,根據(jù)默認城市id獲取區(qū)列表,選中默認區(qū)。
getDefaultOptions = () = >{
let {
province: provinceId,
city: cityId
} = this.props.defaultValue;
//獲取省份
this.props.dispatch({
type: 'basic/getProvinceList',
params: {},
successCallBack: (rs) = >{
let provinceList = rs.provinces;
//獲取城市
let params = {
province_id: +provinceId
};
this.props.dispatch({
type: 'storage/getCityList',
params,
successCallBack: (rs2) = >{
let cityList = rs2.cities;
if (cityList == null) {
cityList = [];
}
if ( + cityId == 0) {
this._getOptions(provinceList, [], []);
return;
}
//獲取區(qū)
let params = {
city_id: +cityId,
};
this.props.dispatch({
type: 'storage/getDistrictList',
params,
successCallBack: (rs3) = >{
let districtList = rs3.districts;
if (districtList == null) {
districtList = [];
}
this._getOptions(provinceList, cityList, districtList);
};
});
}
});
}
});
};
出現(xiàn)3層嵌套的回調(diào),這就是傳說中的“惡魔金字塔”。確實是惡魔呀,可讀性巨差,自己看著都有點暈,更別說其他人了。
都說ES6的Promise對象讓“惡魔金字塔”聞風喪膽,忍不住來體驗一下。
Promise登場
MDN上這樣定義Promise:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
廢話不多說,來看看使用了Promise后的代碼是怎樣的:
sendRequest = (type, params) = >{
return new Promise((resolve, reject) = >{
this.props.dispatch({
type,
params,
successCallBack: (rs) = >{
resolve(rs);
}
});
});
};
getDefaultOptions = () = >{
let {
province: provinceId,
city: cityId
} = this.props.defaultValue;
let provinceList,
cityList,
districtList;
let _promise = this.sendRequest('basic/getProvinceList', {});
_promise.then(rs = >{
provinceList = rs.provinces ? rs.provinces: [];
return this.sendRequest('storage/getCityList', {
province_id: +provinceId
})
}).then(rs = >{
cityList = rs.cities ? rs.cities: [];
//只有省份的情況
if ( + cityId == 0) {
this._getOptions(provinceList, cityList, []);
return Promise.reject({
notRealPromiseException: true,
});
}
return this.sendRequest('storage/getDistrictList', {
city_id: +cityId
});
}).then(rs = >{
districtList = rs.districts ? rs.districts: [];
return this._getOptions(provinceList, cityList, districtList);
}).
catch(ex = >{
if (ex.notRealPromiseException) {
return true;
}
return false;
});
};
需要有序地執(zhí)行異步操作的場景,Promise再適合不過了。相比回調(diào)嵌套,層次更分明,可讀性強。
Promise基本原理學習
無論是在異步操作的執(zhí)行之前或執(zhí)行之后,用Promise對象的then方法注冊回調(diào),回調(diào)都能一致執(zhí)行。
很好奇它是怎么做到的,于是自己嘗試寫了個簡易的Promise, 模擬Promise對異步操作的值的代理:
https://gist.github.com/anonymous/402271e9e9c59958279d0fe096e0a277