首頁 > web前端 > 前端問答 > es6回調地獄是什麼

es6回調地獄是什麼

青灯夜游
發布: 2023-02-14 14:58:54
原創
2002 人瀏覽過

在es6中,回呼地獄就是多層回呼函數相互嵌套,即回呼函數中嵌套回調函數的情況;它是為了實現程式碼順序執行而出現的一種操作,它會造成我們的程式碼可讀性非常差,後期不好維護。 es6中使用promise來解決回調地獄的問題。

es6回調地獄是什麼

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

前言

在正式了解「回呼地獄」之前,我們先了解兩個概念:

1.回呼函數

當一個函數作為參數傳入另一個參數中,並且它不會立即執行,只有當滿足一定條件後該函數才可以執行,這種函數就稱為回調函數。我們熟悉的定時器和Ajax中就存在有回呼函數:

setTimeout(function(){   //function(){console.log('执行了回调函数')}就是回调函数,它只有在3秒后才会执行
	console.log('执行了回调函数');
},3000)  //3000毫秒
登入後複製

這裡的回呼函數是function(){console.log('執行了回呼函數')},在滿足時間3秒後執行。

//1.创建异步对象
			var xhr=new XMLHttpRequest();
      //2.绑定监听事件(接收请求)
			xhr.onreadystatechange=function(){
				//此方法会被调用4次
				//最后一次,readyState==4
				//并且响应状态码为200时,才是我们要的响应结果 xhr.status==200
				if(xhr.readyState==4 && xhr.status==200){
					//把响应数据存储到变量result中
					var result=xhr.responseText;
					console.log(result);
				}
			}
      //3.打开链接(创建请求)
			xhr.open("get","/demo/ajaxDemo",true);
      //4.发送请求
			xhr.send();
登入後複製

這裡的回呼函數是xhr.onreadystatechange綁定的函數,在xhr.send()發送請求並拿到回應後執行。

2、非同步任務

與之相對應的概念是“同步任務”,同步任務在主執行緒上排隊執行,只有前一個任務執行完畢,才能執行下一個任務。非同步任務不進入主線程,而是進入非同步佇列,前一個任務是否執行完畢不影響下一個任務的執行。同樣,也拿定時器作為非同步任務舉例:

setTimeout(function(){
    console.log('执行了回调函数');
},3000)
console.log('111');
登入後複製

如果按照程式碼編寫的順序,應該先輸出“執行了回調函數”,再輸出“111”。但實際輸出為:
es6回調地獄是什麼
這種不阻塞後面任務執行的任務就叫做非同步任務。

接下來讓我們看看什麼是回調地獄。

一、回呼地獄是什麼?

根據前面我們可以得到一個結論:存在非同步任務的程式碼,不能保證能按照順序執行,那如果我們非要程式碼順序執行呢?

比如我要說一句話,語序必須是下面這樣的:武林要以和為貴,要講武德,不要搞窩裡鬥。
我必須要這樣操作,才能保證順序正確:

        setTimeout(function () {  //第一层
            console.log('武林要以和为贵');
            setTimeout(function () {  //第二程
                console.log('要讲武德');
                setTimeout(function () {   //第三层
                    console.log('不要搞窝里斗');
                }, 1000)
            }, 2000)
        }, 3000)
登入後複製

es6回調地獄是什麼

#可以看到,程式碼中的回呼函數套回調函數,居然套了3層,這種回呼函數中巢狀回呼函數的情況就叫做回呼地獄。

總結一下,回呼地獄就是為是實現程式碼順序執行而出現的一種操作,它會造成我們的程式碼可讀性非常差,後期不好維護。

那該如何解決回調地獄呢?

二、如何解決回呼地獄

#1.Promise

Promise是js中的一個原生對象,是一種非同步程式設計的解決方案,可以替換掉傳統的回呼函數解決方案。

  • Promise建構子接收一個函數作為參數,我們需要處理的非同步任務就卸載該函數體內,該函數的兩個參數是resolve,reject。非同步任務執行成功時呼叫resolve函數傳回結果,反之呼叫reject。

  • Promise物件的then方法用來接收處理成功時回應的數據,catch方法用來接收處理失敗時相應的數據。

  • Promise的鍊式程式設計可以保證程式碼的執行順序,前提是每一次在than做完處理後,一定要return一個Promise對象,這樣才能在下一次then時接收到數據。

下面是實例程式碼:

        function fn(str){
            var p=new Promise(function(resolve,reject){
                //处理异步任务
                var flag=true;
                setTimeout(function(){
                    if(flag){
                        resolve(str)
                    }
                    else{
                        reject('操作失败')
                    }
                })
            })
            return p;
        }

        fn('武林要以和为贵')
        .then((data)=>{
            console.log(data);
            return fn('要讲武德');
        })
        .then((data)=>{
            console.log(data);
            return fn('不要搞窝里斗')
        })
        .then((data)=>{
            console.log(data);
        })
        .catch((data)=>{
            console.log(data);
        })
登入後複製

es6回調地獄是什麼
# 但是Promise最大的問題就是程式碼冗餘,原來的非同步任務被Promise封裝一下,不管什麼操作都用than,就會導致一眼看過去全是then…then…then…,這樣也是不利於程式碼維護的。

所以下面的async/await 可以時程式碼看起來更像同步程式碼。

2.async/await

#首先我們看async關鍵字,他作為一個關鍵字放到宣告函數前面,表示函數為一個非同步任務,不會阻塞後面函數的執行:

        async function fn(){
            return '不讲武德';
        }
        console.log(fn());
登入後複製

es6回調地獄是什麼
可以看到async函數傳回資料時自動封裝為一個Promise物件。

和Promise物件一樣,處理非同步任務時也可以按照成功和失敗來返回不同的數據,處理成功時用then方法來接收,失敗時用catch方法來接收數據:

        async function fn() {
            var flag = true;
            if (flag) {
                return '不讲武德';
            }
            else{
                throw '处理失败'
            }
        }
        fn()
        .then(data=>{
            console.log(data);
        })
        .catch(data=>{
            console.log(data);
        })

        console.log('先执行我,表明async声明的函数是异步的');
登入後複製

es6回調地獄是什麼
当把flag设置为false是,执行结果为:
es6回調地獄是什麼
async关键字说完了,我们看看awai关键字

  • await关键字只能在使用async定义的函数中使用
  • await后面可以直接跟一个 Promise实例对象(可以跟任何表达式,更多的是跟一个返回Promise对象的表达式)
  • await函数不能单独使用
  • await可以直接拿到Promise中resolve中的数据。
        //封装一个返回promise的异步任务
        function fn(str) {
            var p = new Promise(function (resolve, reject) {
                var flag = true;
                setTimeout(function () {
                    if (flag) {
                        resolve(str)
                    } else {
                        reject('处理失败')
                    }
                })
            })
            return p;
        }

        //封装一个执行上述异步任务的async函数
        async function test(){
            var res1=await fn('武林要以和为贵');  //await直接拿到fn()返回的promise的数据,并且赋值给res
            var res2=await fn('要讲武德');
            var res3=await fn('不要搞窝里斗');
            console.log(res1,res2,res3);
        }
        //执行函数
        test();
登入後複製

结果为:
es6回調地獄是什麼
为什么叫await等待呢,因为当代码执行到async函数中的await时,代码就在此处等待不继续往下执行,知道await拿到Promise对象中resolve的数据,才继续往下执行,这样就保证了代码的执行顺序,而且使异步代码看起来更像同步代码。

总结

总结一下,当我们写代码遇到异步回调时,我们想让异步代码按照我们想要的顺序执行,如果按照传统的嵌套方式,就会出现回调地狱,这样的代码不利于维护,我们可以通过Promise对象进行链式编程来解决,这样尽管可以解决问题,但是ES7给我们提供了更加舒适的async/await语法糖,可以使得异步代码看起来更像是同步代码。

【相关推荐:javascript视频教程web前端

以上是es6回調地獄是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板