Promise解决回调地狱

回调地狱:前端的ajax和jsonp内部充斥着大量的异步,为了能够拿到异步的数据,使用了大量的回调函数,来获取将来异步执行成功之后的数据。如果请求不多,还好,一旦请求的数量达到一定程度,并且复杂度提升以后,会造成一些问题。

	// 开启三个异步的程序,要求能同时拿到所有异步的结果
	// 在一个异步成功之后,才能执行下一个程序,下一个程序还是异步
    ajax({
        url:"http://localhost/promise/data/d1.php",
        success:function(res1){
            console.log(res1);
            ajax({
                url:"http://localhost/promise/data/d2.php",
                success:function(res2){
                    console.log(res2);
                    ajax({
                        url:"http://localhost/promise/data/d3.php",
                        success:function(res3){
                            console.log(res3);
                            console.log(res1, res2, res3);
                        }
                    })
                }
            })
        }
    })
    // 将三个res做个拼接,以上使用了回调地域的写法 

在新版本出现之后,在新的语法中,提供了一些更优雅得处理方案

  1. Promise(ES6)
    promise,承诺,事件发生在将来,成功或失败都是在将来才会发生,但是在承诺开始得时刻,就需要提前预置,发生了成功,必然不会执行失败,发生了失败,必然不会执行成功。
    语法:
    Promise是一个构造函数,new的同时立即传参,参数是回调函数,回调函数身上可以接受两个参数,分别是:resolve(success,成功),reject(error,失败)
    var p = new Promise(function(a,b){
    // 正在执行…
    // 此处放置异步的程序
    // a就是在then中的第一个回调函数,表示成功要做的事情
    / b就是在catch中的第一个回调函数,表示失败要做的事情
    });
    p.then(function(){
    // 成功的预置函数
    });
    p.catch(function(){
    // 失败的预置函数
    });
// 语法
    var p = new Promise(function(a,b){
        // 正在执行....
        // 此处放置异步的程序
        setTimeout(() => {
            // a就是在then中的第一个回调函数,表示成功要做的事情
            // console.log(1);
            a();
        }, Math.random() * 1000);
        
        setTimeout(() => {
            // b就是在catch中的第一个回调函数,表示失败要做的事情
            // console.log(2);
            b();
        }, Math.random() * 1000);

    });
    var p2 = p.then(function(){
        // 成功的预置函数
        console.log("成功");
        // 又返回了一个promise对象,那么是可以连缀执行
        return p1;  //假设p1是个promise对象
    });

    p2.then(function(){
        
    })

    p.catch(function(){
        // 失败的预置函数
        console.log("失败");
    });

以下代码需要引入ajax.js,并且为了方便观察,将其放入一个点击事件里

	// promise解决回调地域-没有保存变量版
    var p1 = new Promise(function(success,error){
        ajax({
            url:"http://localhost/promise/data/d1.php",
            success:function(res1){
                // console.log(res1);
                success(res1);
            }
        })
    }).then(function(r1){
        console.log(r1);
        return new Promise(function(success,error){
            ajax({
                url:"http://localhost/promise/data/d2.php",
                success:function(res2){
                    success(res2);
                }
            })
        });
    }).then(function(r2){
        console.log(r2);
        return new Promise(function(success,error){
            ajax({
                url:"http://localhost/promise/data/d3.php",
                success:function(res3){
                    success(res3);
                }
            })
        })
    }).then(function(r3){
        console.log(r3);
    })
    // promise解决回调地域-保存变量版
    var p1 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d1.php",
            success:function(res1){
                resolve(res1);
            }
        })
    })
    var p2 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d2.php",
            success:function(res2){
                resolve(res2);
            }
        })
    })
    var p3 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d3.php",
            success:function(res3){
                resolve(res3);
            }
        })
    })
    p1.then(function(r1){
        console.log(r1);
        return p2;
    }).then(function(r2){
        console.log(r2);
        return p3;
    }).then(function(r3){
        console.log(r3);
    })

新的需求:如何在一个位置拿到所有?使用promise得批处理

    var p1 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d1.php",
            success:function(res1){
                resolve(res1);
            }
        })
    })
    var p2 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d2.php",
            success:function(res2){
                resolve(res2);
            }
        })
    })
    var p3 = new Promise(function(resolve){
        ajax({
            url:"http://localhost/promise/data/d3.php",
            success:function(res3){
                resolve(res3);
            }
        })
    })
    // 批处理-all:全部成功,即为成功(拿到的数据是所有数据),只要有一个失败,即为失败
    // Promise.all([p1,p2,p3]).then(function(sum){
    //     console.log(sum);
    // })

    // 批处理-race:得到最先结束的状态,不管是成功(当前成功的数据)还是失败
    Promise.race([p1,p2,p3]).then(function(sum){
        console.log(sum);
    })

ajax.js的代码:

function ajax(ops){
    ops.type = ops.type || "get";
    ops.data = ops.data || "";
    // ops.url = ops.type=="get" ? ops.url + "?" + ops.data : ops.url;
    if(ops.type=="get"){
        // 在get请求时,使用时间戳避免,缓存问题
        let t = new Date().getTime();
        ops.url = ops.url + "?__qft="+ t + "&" + ops.data;
    }
    var xhr = new XMLHttpRequest();
    xhr.open(ops.type, ops.url);
    if(ops.type == "get"){
        xhr.send();
    }else{
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xhr.send(ops.data);
    }
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && xhr.status === 200){
            ops.success(xhr.responseText);
        }
    }
}

可将上述代码封装到ajax-promise.js文件中

// 当前ajax封装完成之后的调用方式:
// var p1 = ajax({
//     type:"get",
//     url:"",
//     data:{
//         user:"admin",
//         pass:123
//     }
// })
// p1.then(function(res){
//     console.log(res)
// })
// p1.catch(function(res){
//     console.log(res)
// })


// ajax函数自身执行的时候不再接收成功和失败的处理函数了
// 交给ajax内部封装的promise处理


// 封装过程
function ajax(ops){
    ops.type = ops.type || "get";
    ops.data = ops.data || {};
    var str = "";
    for(var key in ops.data){
        str += `${key}=${ops.data[key]}&`;
    }
    if(ops.type=="get"){
        let t = new Date().getTime();
        ops.url = ops.url + "?" + str + "__qft="+ t;
    }
    var xhr = new XMLHttpRequest();
    xhr.open(ops.type, ops.url);
    if(ops.type == "get"){
        xhr.send();
    }else{
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xhr.send(ops.data);
    }
    return new Promise(function(resolve,reject){
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                resolve(xhr.responseText);
            }else if(xhr.readyState === 4 && xhr.status !== 200){
                reject("当前请求失败了,失败的原因是:" + xhr.status);
            }
        }
    })
}
  1. 在Promise的基础上,再使用async/await(ES7)
    async function fn(){
    var res1 = await new Promise(…)
    var res2 = await new Promise(…)
    var res3 = await new Promise(…)
    var res4 = await new Promise(…)
    console.log(res1,res2,res3,res4);
    }
    因为是在promise的基础上的语法,而ajax里面有promise,所以也可以直接调用ajax-promise.js
<script src="../ajax-promise.js"></script>
<script>
    // async/await

    async function fn(abc){
        var p1 = await ajax({
            url:"http://localhost/async-await/data/d1.php"
        });
        
        var p2 = await ajax({
            url:"http://localhost/async-await/data/d12312.php"
        });

        var p3 = await ajax({
            url:"http://localhost/async-await/data/d3.php"
        });
        
        var p3 = await ajax({
            url:"http://localhost/async-await/data/d3.php"
        });
        
        var p3 = await ajax({
            url:"http://localhost/async-await/data/d3.php"
        });

        console.log(p1, p2, p3);

        console.log(abc);
    }

    document.onclick = function(){
        fn("hello world");
    }

</script>

promise是用来处理所有的异步的回调地狱,不止是ajax,任何一个异步,只要是回调地狱的调用形式,就可以使用promise改造。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值