JS--回调地狱及解决方法

回调地狱

​ 前端的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);
                     }
                 })
             }
         })
     }
 })

回调地狱的缺点:

  • 上边的例子用回调地狱能解决问题,但是有缺点,或者说不优雅。
  • 如果最里面的异步没有执行结束,外面所有的程序是不是都相当于没有结束,有点递归的影子,非常消耗性能。
  • 格式非常不优雅,语义化非常差,不方便调错。

回调地狱的解决方法

​ 在js新版本出现之前,回调地狱自身就是解决方式,新版本出现之后,在新的语法中,提供了一些更优雅的处理方案。

1.Promise(ES6)解决

语法:(语言的法律法规,固定!!!!!)
Promise是一个构造函数
new的同时立即传参,参数是回调函数,回调函数身上可以接受两个参数,分别是:resolve(success,成功),reject(error,失败)

var p = new Promise(function(a,b){
	// 正在执行....
	// 此处放置异步的程序
	// a就是在then中的第一个回调函数,表示成功要做的事情
	// b就是在catch中的第一个回调函数,表示失败要做的事情
});
p.then(function(){
	// 成功的预置函数
});
p.catch(function(){
	// 失败的预置函数
});

promis和ajax解决上边的例子

 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的封装

// 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);
            }
        }
    })
}

当前ajax封装完成之后的调用方式:

// 当前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)
 })

2.async/await(ES7)解决

在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);
 }

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");
    }

总结

  • promise就是一种固定语法,固定写法,固定传输。
  • 所有的原理都在promise的内部被封装。
  • promise是用来处理所有的异步的回调地狱,不止是ajax,任何一个异步,只是是回调地狱的调用形式,就可以使用promise改造。
发布了18 篇原创文章 · 获赞 35 · 访问量 2161

猜你喜欢

转载自blog.csdn.net/wxd_97/article/details/104869575