引语
场景:工作中遇到一个数据接口同时依赖于另外两个接口的情况,
需要两个接口返回的数据才能实现进一步操作,下面介绍 3 种方法
首先普及一下promise的一些冷门知识
执行 then 和 catch 会返回一个新的 Promise ,该 Promise 最终状态根据 then 和 catch 的回调函数的执行结果决定
- 如果回调函数最终是 throw , 该 Promise 是 rejected 状态
- 如果回调函数最终是 return , 该 Promise 是 resolved 状态
- 但如果回调函数最终 return 了一个 Promise , 该 Promise 会和回调函数的 reurn 的状态保持一致
利用js回调嵌套的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function getDepartmentsList(callback){ var departmentList = Math.ceil(Math.random()*1000) setTimeout(function(){ callback(departmentList) },Math.random()*1000) }
function getLevelList(callback){ var levelList = Math.ceil(Math.random()*1000)+1000 setTimeout(function(){ callback(levelList) },Math.random()*1000) }
function registrationList(departmentList,levelList,callback){ var percent = Math.ceil(departmentList/levelList*100) setTimeout(function(){ callback(percent) },Math.random()*1000) }
|
利用es6的promise解决回调地狱问题
《ES6标准入门》对Promise的描述
所谓Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道的结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进一步处理。
MDN对Promise的描述:
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
当时看到Promise最头疼的,就是初学者看起来匪夷所思,也是最被js程序员广为称道的特性:then函数调用链。
then函数调用链,从其本质上而言,就是对多个异步过程的依次调用,本文就从这一点着手,对Promise这一特性进行研究和学习。
Promise的相关知识,请参阅 Promise的链式调用
基于以上对Promise的了解,我们知道可以使用它来解决多层回调嵌套后的代码蠢笨难以维护的问题。下面请看具体代码:
每个异步接口 返回一个promise对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function getDepartmentsList(){ return new Promise(function(resolve,reject){ var departmentList = Math.ceil(Math.random()*1000) setTimeout(function(){ resolve(departmentList) },Math.random()*1000) }) }
function getLevelList(){ return new Promise(function(resolve,reject){ var levelList = Math.ceil(Math.random()*1000)+1000 setTimeout(function(){ resolve(levelList) },Math.random()*1000) }) }
function registrationList(departmentList,levelList){ return new Promise(function(resolve,reject){ var percent = Math.ceil(departmentList/levelList*100) setTimeout(function(){ resolve(percent) },Math.random()*1000) }) }
|
利用promise.all方法保证接口数据成功返回再执行操作
1 2 3 4 5 6
| Promise.all([getDepartmentsList(),getLevelList()]).then(function([departmentList,levelList]){ registrationList(departmentList,levelList).then(function(percent){ console.log(percent) }) })
|
Axios 解决方案(VUE)
每个异步接口 返回一个axios对象
1 2 3 4 5 6 7 8
| getDepartmentsList () { return axios.get(process.env.BASE_API_WAP + 'category/2'); },
getLevelList () { return axios.get(process.env.BASE_API_WAP + 'category/3'); }
|
利用axios.all方法执行多个并发请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| filterData (targetArray) { targetArray.forEach(item => { for (let key in this.departmentsList) { if (Number(item.departments) === this.departmentsList[key].id) { item.departments = this.departmentsList[key].name; } } for (let key in this.levelList) { if (Number(item.level) === this.levelList[key].id) { item.level = this.levelList[key].name; } } }); }
init () { this.title = ''; registrationList(this.current, this.pageSize, this.title).then(data => { this.data = data.content; this.filterData(this.data); this.totalSize = data.total; this.pages = data.pages; }).catch(error => { console.log(error); }); }
mounted () { let _this = this; axios.all([this.getDepartmentsList(), this.getLevelList()]) .then(axios.spread(function (list1, list2) { _this.departmentsList = list1.data; _this.levelList = list2.data; _this.init(); })); }
|
总结
前端解决异步的问题时常都会遇到,Promise给前端程序员带来了新的解决思路,在它基础之上的promise的工具库(如Axios),也是在此上的封装。只要明白了其中的原理,在什么开发框架下都能灵活运用。