本篇內(nèi)容介紹了“介紹JS異步的執(zhí)行原理和回調(diào)方法”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
建網(wǎng)站原本是網(wǎng)站策劃師、網(wǎng)絡(luò)程序員、網(wǎng)頁設(shè)計(jì)師等,應(yīng)用各種網(wǎng)絡(luò)程序開發(fā)技術(shù)和網(wǎng)頁設(shè)計(jì)技術(shù)配合操作的協(xié)同工作。創(chuàng)新互聯(lián)專業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),網(wǎng)站制作(企業(yè)站、響應(yīng)式網(wǎng)站、電商門戶網(wǎng)站)等服務(wù),從網(wǎng)站深度策劃、搜索引擎友好度優(yōu)化到用戶體驗(yàn)的提升,我們力求做到極致!??我們知道JavaScript是單線程的,而瀏覽器是多線程的。單線程執(zhí)行任務(wù)需要一個(gè)個(gè)排隊(duì)進(jìn)行,假如一個(gè)任務(wù)需要很長時(shí)間執(zhí)行(像ajax需要較長時(shí)間),會直接導(dǎo)致無響應(yīng),后面的任務(wù)一直在等待執(zhí)行。這時(shí)候就需要用到異步。
??想了解異步,首先我們要知道瀏覽器有最基本的三個(gè)常駐線程: JS引擎線程,事件觸發(fā)線程,GUI渲染線程。
??其中JS引擎線程和事件觸發(fā)線程共同構(gòu)成了一種事件循環(huán)機(jī)制,而GUI渲染線程與JS引擎是互斥的,當(dāng)JS引擎執(zhí)行時(shí)GUI線程會被掛起,GUI更新保存在一個(gè)隊(duì)列中,當(dāng)JS引擎空閑時(shí),立即被執(zhí)行。
??我們從它的事件循環(huán)機(jī)制解析:
??JS引擎線程中分為同步和異步任務(wù):
????1.同步任務(wù)全部通過主線程執(zhí)行,形成執(zhí)行棧。
????2.當(dāng)有異步任務(wù)時(shí)交給異步進(jìn)程(WebAPIs):包含事件觸發(fā)線程或者定時(shí)器線程等處理,形成任務(wù)隊(duì)列。
????3.當(dāng)執(zhí)行棧中的任務(wù)全部處理完成,主線程為空閑的時(shí)候,會從任務(wù)隊(duì)列中提取任務(wù)到執(zhí)行棧中執(zhí)行。
??通俗來說,JavaScript除了主線程之外還存在一個(gè)任務(wù)隊(duì)列,任務(wù)隊(duì)列存放需要異步執(zhí)行的內(nèi)容,執(zhí)行完主線程后,就會不斷循環(huán)掃描執(zhí)行任務(wù)隊(duì)列的任務(wù),直至隊(duì)列清空。
畫解:
??如圖小明因?yàn)閷W(xué)習(xí)耗時(shí)長會,如果沒做完就會一直無法玩DNF游戲了,就把學(xué)習(xí)放到了異步任務(wù)隊(duì)列中,等玩完游戲(主線程)再學(xué)習(xí)(任務(wù)隊(duì)列)。期間母親添加學(xué)習(xí)事件(DOM事件),小明每完成一個(gè)學(xué)習(xí)任務(wù)就看看還有啥任務(wù)(循環(huán)掃描),直至最后做完.
??下面再看一個(gè)例子(瀏覽器刷新不斷點(diǎn)擊按鈕):
let myData = null //ajax請求 function ajax() { //騰訊新冠實(shí)時(shí)數(shù)據(jù)接口,僅做學(xué)習(xí) axios.get('https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=chinaDayList,chinaDayAddList,nowConfirmStatis,provinceCompare') .then(data => { console.log("ajax返回成功"); myData = data.data console.log(myData); }) .catch(error => { console.log("ajax返回失敗"); }) } console.log(myData); ajax() setTimeout(() => { console.log('定時(shí)器'); }, 2000); console.log(myData); const btn = document.querySelector('button') btn.onclick = () => { console.log("點(diǎn)擊了"); }
null
null
ajax返回成功
Object
點(diǎn)擊了
定時(shí)器
點(diǎn)擊了
??可以看到,console在主線程中是同步執(zhí)行的,先執(zhí)行,而在主線程外的任務(wù)隊(duì)列,存放著異步執(zhí)行的內(nèi)容,這里是setTimeout,ajax和DOM事件,按照任務(wù)隊(duì)列順序執(zhí)行(循環(huán)掃描隊(duì)列)。
??為什么要循環(huán)掃描呢?
??通過點(diǎn)擊事件可以看出,當(dāng)用戶進(jìn)行交互時(shí)(點(diǎn)擊事件,滾動事件,窗口大小變化事件等),會向事件循環(huán)中的任務(wù)隊(duì)列添加新事件,然后等待執(zhí)行,所以需要循環(huán)掃描。
??既然異步都是放在最后的任務(wù)隊(duì)列執(zhí)行,那么我們很多邏輯就難以實(shí)現(xiàn),這時(shí)候我們需要處理這種異步邏輯,最常用的方式是回調(diào)——回頭調(diào)用。
回調(diào)函數(shù):簡單來說就是,函數(shù)A中傳入函數(shù)B作為參數(shù)時(shí),函數(shù)B即為A函數(shù)執(zhí)行的回調(diào)函數(shù)?;卣{(diào)有嵌套回調(diào)和鏈?zhǔn)交卣{(diào)兩種。
??下面是回調(diào)的一個(gè)簡單用法:
let myData = null console.log(myData); setTimeout(() => { console.log('定時(shí)器'); }, 2000); const btn = document.querySelector('button') btn.onclick = () => { console.log("點(diǎn)擊了"); } let name = "張三" function hr(callback) { setTimeout(() => { console.log(`我是${name}`); callback(); }, 2001); } console.log(myData); function gj() { console.log(`${name}你好,我是李四,認(rèn)識一下吧`); } hr(gj)
null
null
點(diǎn)擊了
定時(shí)器
我是張三
張三你好,我是李四,認(rèn)識一下吧
點(diǎn)擊了
??很明顯的看到,當(dāng)我們函數(shù)需要用到數(shù)據(jù)的時(shí)候就用到了回調(diào),這里用到的是異步回調(diào)。
??回調(diào)雖然是解決異步常用的方法,可是伴隨著JS日益復(fù)雜的需求。同步異步需要越來越多的回調(diào)實(shí)現(xiàn)邏輯。同異步的混雜和過多的回調(diào)嵌套和縮進(jìn)使得代碼變得難以解讀和維護(hù),形成“回調(diào)地獄”。
??我們看一個(gè)例子:
const verifyUser = function(username, password, callback){ dataBase.verifyUser(username, password, (error, userInfo) => { if (error) { callback(error) }else{ dataBase.getRoles(username, (error, roles) => { if (error){ callback(error) }else { dataBase.logAccess(username, (error) => { if (error){ callback(error); }else{ callback(null, userInfo, roles); } }) } }) } }) };
大多數(shù)人光是看到上面的代碼就感受到了腦子凍結(jié)的滋味,如果一個(gè)項(xiàng)目里擁有上百個(gè)這樣的代碼塊,過一段時(shí)間,我相信連編寫他的人都會頭疼。來到自己的項(xiàng)目就像是來到了地獄。
??最主要的是,與此同時(shí)回調(diào)還存在信任問題,他把執(zhí)行控制權(quán)交給了某個(gè)第三方(比如ajax)。為了解決信任問題,我們必須在程序?qū)懜鞣N邏輯來解決回調(diào)帶來的信任問題。
??·調(diào)用過早
??·調(diào)用過完
??·調(diào)用次數(shù)過多過少,沒有把需要的參數(shù)成功傳給回調(diào)函數(shù),
??·可能出現(xiàn)的錯(cuò)誤被吞。
??可以發(fā)現(xiàn)寫特定邏輯來解決特定的信任問題,已經(jīng)使得難度大于本身應(yīng)用價(jià)值了,還會造成代碼冗雜,可讀性差等問題。
??綜上:回調(diào)解決異步存在缺陷:
?????1)不符合人對任務(wù)處理的邏輯思維
?????2)回調(diào)帶來的信任問題。
??面對回調(diào)日益明顯的弊端,ES6更新了Promise用來解決異步問題。下一篇寫ES6——Promise。
“介紹JS異步的執(zhí)行原理和回調(diào)方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!