"回调地狱"——优雅解决之Promise 实例
"回调地狱"是什么
”回调地狱“也叫”回调金字塔“,我们平时写代码的时候 js如果异步 回调是不可避免的
例如 ajax不断的进行异步请求数据 回调方法里还要对数据进行处理,继续回调...形成回调地狱
这会使得我们的代码可读性变差,出现问题 不好调试 也会导致性能下降
而nodejs 是一种单线程的事件驱动而且是非阻塞的I/O模型,而I/O模型,是异步的,这样nodejs在处理结果的时候 就需要在回调函数中执行,这样也就形成了回调地狱。
那我们应该如何优雅的避免回调地狱呢
递归?No! 递归用在一些简单的场景下还是很方便的,例如快速排序,哈哈,但是在处理复杂的逻辑上,似乎有点不合适..
jQuery 1.5提供了jQuery.when() then()方法 differ对象
具体可以看一下api:http://www.css88.com/jqapi-1.9/jQuery.when/
es6 =>Promise、Generator以及 es7 => Async
- Promise
是一个构造函数,用来传递异步操作消息,链式调用,避免层层嵌套的回调函数。
promise接收两个函数参数,resolve和reject,分别表示异步操作执行成功后的回调和失败的回调
promise在声明的时候就已经执行了
有三种状态:pending进行中、resolve已完成、rejected已失败,
这些状态只能由pending -> resolved, pending -> rejected,一旦promise实例发生改变,就不能在变了,任何时候都能得到这个结果
例子一:用三个小球依次向右运动
1 function moving(obj, left){ 2 //创建一个promise实例 并传入两个函数参数 来设置promise的状态 3 return new Promise(function(resolve,reject){ 4 var leftPos = parseInt(obj.css('margin-left')); 5 if(leftPos != left){ 6 var timer = setInterval(()=>{ 7 leftPos += 2; 8 obj.css('margin-left',leftPos); 9 10 if(leftPos == left){ 11 clearInterval(timer) 12 resolve() //成功 运动完成之后 返回一个状态resolved then接收到后继续执行下一个回调 13 } 14 },10) 15 }else{ 16 resolve() 17 } 18 }) 19 } 20 //采用promise链式操作的方式 通过传递状态的方式来调用回调函数 21 moving($('.b1'),100) 22 .then(function(){ //当b1运动完成 并且成功之后 链式调用b2 23 return moving($('.b2'),200) //then函数返回的是一个新的promise对象,继续then 24 }) 25 .then(function(){ //当b2运动完成 并且成功之后 链式调用b3 26 return moving($('.b3'),300) 27 })
例子二:ajax 异步调用
ajax异步回调问题,我们要优雅的避免各种回调嵌套,这里我将做一个例子:分别请求两个接口,等到数据都拿到 在进行业务处理
1 //获得商品列表 实例化promise 并传入resolve 和 reject两个参数 2 var getGoodsList = new Promise(function(resolve,reject){ 3 axios.get('/ggserver/api/products/list',{params}) 4 .then(function(res){ 5 if(res.data.code == '200'){ 6 resolve(res.data.result) //成功 7 }else{ 8 reject(res.data.errMsg) //失败 9 } 10 }) 11 }) 12 //我们在请求一个分类列表 13 var getGoodsType = new Promise(function(resolve,reject){ 14 axios.get('/ggserver/api/goodsType') 15 .then(function(res){ 16 if(res.data.code == '200'){ 17 resolve(res.data.result) //成功 18 }else{ 19 reject(res.data.errMsg) //失败 20 } 21 }) 22 }) 23 然后。在将获得的数据进行业务处理 24 getGoodsList.then(function(goodslistdata){ 25 //处理业务 26 }).catch(function(errMsg){ 27 //失败业务 28 console.log('哎,goodslist运气不佳...') 29 }) 30 31 getGoodsType.then(function(goodsTypedata){ 32 //处理业务 33 }).catch(function(errMsg){ 34 //失败业务 35 console.log('哎,goodstyoe运气不佳...') 36 }) 37 38 最后 我们通过promise.all()方法来 等列表 和 类型加载完 进行其他业务处理 39 Promise.all([getGoodsList, getGoodsType]).then(function([data1,data2]){ 40 console.log(data1,data2,'已经加载完成啦') 41 })
案例出处 https://segmentfault.com/a/1190000012423825微博