es6回調地獄是什麼
在es6中,回呼地獄就是多層回呼函數相互嵌套,即回呼函數中嵌套回調函數的情況;它是為了實現程式碼順序執行而出現的一種操作,它會造成我們的程式碼可讀性非常差,後期不好維護。 es6中使用promise來解決回調地獄的問題。
本教學操作環境: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”。但實際輸出為:
這種不阻塞後面任務執行的任務就叫做非同步任務。
接下來讓我們看看什麼是回調地獄。
一、回呼地獄是什麼?
根據前面我們可以得到一個結論:存在非同步任務的程式碼,不能保證能按照順序執行,那如果我們非要程式碼順序執行呢?
比如我要說一句話,語序必須是下面這樣的:武林要以和為貴,要講武德,不要搞窩裡鬥。
我必須要這樣操作,才能保證順序正確:
setTimeout(function () { //第一层 console.log('武林要以和为贵'); setTimeout(function () { //第二程 console.log('要讲武德'); setTimeout(function () { //第三层 console.log('不要搞窝里斗'); }, 1000) }, 2000) }, 3000)
#可以看到,程式碼中的回呼函數套回調函數,居然套了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); })
# 但是Promise最大的問題就是程式碼冗餘,原來的非同步任務被Promise封裝一下,不管什麼操作都用than,就會導致一眼看過去全是then…then…then…,這樣也是不利於程式碼維護的。
所以下面的async/await 可以時程式碼看起來更像同步程式碼。
#首先我們看async
關鍵字,他作為一個關鍵字放到宣告函數前面,表示函數為一個非同步任務,不會阻塞後面函數的執行:
async function fn(){ return '不讲武德'; } console.log(fn());
可以看到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声明的函数是异步的');
当把flag设置为false是,执行结果为: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();
结果为:
为什么叫await
等待呢,因为当代码执行到async
函数中的await
时,代码就在此处等待不继续往下执行,知道await
拿到Promise对象中resolve的数据,才继续往下执行,这样就保证了代码的执行顺序,而且使异步代码看起来更像同步代码。
总结
总结一下,当我们写代码遇到异步回调时,我们想让异步代码按照我们想要的顺序执行,如果按照传统的嵌套方式,就会出现回调地狱,这样的代码不利于维护,我们可以通过Promise对象进行链式编程来解决,这样尽管可以解决问题,但是ES7给我们提供了更加舒适的async/await语法糖,可以使得异步代码看起来更像是同步代码。
【相关推荐:javascript视频教程、web前端】
以上是es6回調地獄是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在ES6中,可以利用數組物件的reverse()方法來實現數組反轉,該方法用於顛倒數組中元素的順序,將最後一個元素放在第一位,而第一個元素放在最後,語法「array.reverse()」。 reverse()方法會修改原始數組,如果不想修改需要配合擴充運算子「...」使用,語法「[...array].reverse()」。

async是es7的。 async和await是ES7中新增內容,是對於非同步操作的解決方案;async/await可以說是co模組和生成器函數的語法糖,用更清晰的語意解決js非同步程式碼。 async顧名思義是「非同步」的意思,async用於聲明一個函數是異步的;async和await有一個嚴格規定,兩者都離不開對方,且await只能寫在async函數中。

為了瀏覽器相容。 ES6作為JS的新規範,加入了許多新的語法和API,但現代瀏覽器對ES6新特性支援不高,所以需將ES6程式碼轉換為ES5程式碼。在微信web開發者工具中,會預設使用babel將開發者ES6語法程式碼轉換為三端都能很好支援的ES5的程式碼,幫助開發者解決環境不同所帶來的開發問題;只需要在專案中配置勾選好「ES6轉ES5」選項即可。

步驟:1、將兩個陣列分別轉換為set類型,語法「newA=new Set(a);newB=new Set(b);」;2、利用has()和filter()求差集,語法“ new Set([...newA].filter(x =>!newB.has(x)))”,差集元素會被包含在一個set集合中返回;3、利用Array.from將集合轉為數組類型,語法“Array.from(集合)”。

es5中可以利用for語句和indexOf()函數來實現數組去重,語法“for(i=0;i<數組長度;i++){a=newArr.indexOf(arr[i]);if(a== -1){...}}」。在es6中可以利用擴充運算子、Array.from()和Set來去重;需要先將陣列轉為Set物件來去重,然後利用擴充運算子或Array.from()函數來將Set物件轉回數組即可。

在es6中,暫時性死區是語法錯誤,是指let和const命令使區塊形成封閉的作用域。在程式碼區塊內,使用let/const指令宣告變數之前,變數都是不可用的,在變數宣告之前屬於該變數的「死區」;這在語法上,稱為「暫時性死區」。 ES6規定暫時性死區和let、const語句不出現變量提升,主要是為了減少運行時錯誤,防止在變量聲明前就使用這個變量,從而導致意料之外的行為。

不是,require是CommonJS規範的模組化語法;而es6規範的模組化語法是import。 require是運行時加載,import是編譯時加載;require可以寫在程式碼的任意位置,import只能寫在文件的最頂端且不可在條件語句或函數作用域中使用;require運行時才引入模組的屬性所以效能相對較低,import編譯時引入模組的屬性所所以效能稍高。

在es6中,可以利用array物件的length屬性來判斷數組裡總共有多少項,即取得數組中元素的個數;該屬性可傳回數組中元素的數組,只需要使用「array.length」語句即可傳回表示數組物件的元素個數的數值,也就是長度值。
