您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)javascript異步的作用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
我們知道JavaScript的單線程的,這與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準(zhǔn)?
所謂"單線程",就是指一次只能完成一件任務(wù)。如果有多個任務(wù),就必須排隊,前面一個任務(wù)完成,再執(zhí)行后面一個任務(wù),以此類推。
這種模式的好處是實現(xiàn)起來比較簡單,執(zhí)行環(huán)境相對單純;壞處是只要有一個任務(wù)耗時很長,后面的任務(wù)都必須排隊等著,會拖延整個程序的執(zhí)行。常見的瀏覽器無響應(yīng)(假死),往往就是因為某一段Javascript代碼長時間運(yùn)行(比如死循環(huán)),導(dǎo)致整個頁面卡在這個地方,其他任務(wù)無法執(zhí)行。
ajax的同步請求就會導(dǎo)致瀏覽器產(chǎn)生假死,因為它會鎖定瀏覽器的UI(按鈕,菜單,滾動條等),并阻塞所有用戶的交互,jquery中的ajax有這樣一個同步請求的功能,一定要慎用,尤其是在請求的數(shù)據(jù)量很大的時候,要避免使用同步請求。
舉幾個栗子感受一下異步
后臺接口使用easy-mock,官方地址:https://easy-mock.com/
ajax使用axios,基本代碼如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>javascript異步</title> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <button>點擊</button> <script> { let myData = null //ajax請求 function ajax() { axios.get('https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(data => { console.log("ajax返回成功");// handle success myData = data.data console.log(myData); }) .catch(error => { // console.log(error); // handle error console.log("ajax返回失敗"); }) } } </script> </body> </html>
我們通過添加一些js來看下效果,
console.log(myData); setTimeout(() => { console.log('定時器'); }, 2000); console.log(myData);
輸出,應(yīng)該沒什么懸念
//null //null //定時器
執(zhí)行順序:
先執(zhí)行第一個 console.log(myData);
然后遇到了定時器,將定時器掛起(就是暫停了這個定時器)
繼續(xù)執(zhí)行第二個 console.log(myData);
沒有可以執(zhí)行的js代碼,回頭把掛起的任務(wù)繼續(xù)執(zhí)行下去
繼續(xù)看下一個栗子
console.log(myData); ajax() console.log(myData);
看下輸出,依然沒有懸念
//null //null //ajax返回成功 //{success: true, data: {…}}(這是接口返回的數(shù)據(jù),我們不必關(guān)心返回的具體內(nèi)容,只要知道返回了就好,陌上寒注)
執(zhí)行順序和上面的定時器基本類似,不在此贅述。
將兩個栗子合并,我們看下
console.log(myData); ajax() setTimeout(() => { console.log('定時器'); }, 2000); console.log(myData);
輸出,
//null //null //ajax返回成功 //{success: true, data: {…}} //定時器
發(fā)現(xiàn)問題了嗎?兩個異步函數(shù)相遇了,先執(zhí)行誰?誰跑的快就先執(zhí)行誰?
也可以這么說,其實這引發(fā)了另外一個知識點,
兩個 console.log(myData);是同步執(zhí)行的,他們都在js的主線程上執(zhí)行,
在主線程之外還存在一個任務(wù)隊列,任務(wù)隊列中存放著需要異步執(zhí)行的內(nèi)容
當(dāng)主線程運(yùn)行完畢之后,就會去執(zhí)行任務(wù)隊列中的任務(wù)(不斷的重復(fù)掃描)直到任務(wù)隊列清空
觀察這段代碼
console.log(1); setTimeout(function () { console.log(2); }, 1000); console.log(3);
輸出:1,3,2,這沒什么可解釋的
再看一段代碼
setTimeout(function(){console.log(1);}, 0); console.log(2);
輸出:2,1,為什么會這樣?
console.log(2);在主線程中,先執(zhí)行,
setTimeout(function(){console.log(1);}, 0);放在了任務(wù)隊列中,
只有在主線程執(zhí)行完了才會去執(zhí)行任務(wù)列隊中的內(nèi)容
看這段代碼,有助于你的理解
console.log(myData); ajax() setTimeout(() => { console.log('定時器'); }, 2000); console.log(myData); const btn = document.querySelector('button') btn.onclick = () => { console.log("點擊了"); }
我們?yōu)閎utton按鈕添加了點擊事件,在瀏覽器刷新的同時不停地對按鈕進(jìn)行點擊操作(當(dāng)然是手動點擊)
看下輸出:
//null //null //(10次輸出)點擊了 //ajax返回成功 //{success: true, data: {…}} //定時器 //點擊了
這樣是不是可以理解為什么主線程要去循環(huán)掃描任務(wù)列隊了?
事件循環(huán)的每一輪稱為一個tick(有沒有聯(lián)想到vue中的nextTick?)
當(dāng)產(chǎn)生用戶交互(鼠標(biāo)點擊事件,頁面滾動事件,窗口大小變化事件等等),ajax,定時器,計時器等,會向事件循環(huán)中的任務(wù)隊列添加事件,然后等待執(zhí)行,
定時任務(wù):setTimeout,setInverval
網(wǎng)絡(luò)請求:ajax請求,img圖片的動態(tài)加載
事件綁定或者叫DOM事件,比如一個點擊事件,我不知道它什么時候點,但是在它點擊之前,我該干什么還是干什么。用addEventListener注冊一個類型的事件的時候,瀏覽器會有一個單獨的模塊去接收這個東西,當(dāng)事件被觸發(fā)的時候,瀏覽器的某個模塊,會把相應(yīng)的函數(shù)扔到異步隊列中,如果現(xiàn)在執(zhí)行棧中是空的,就會直接執(zhí)行這個函數(shù)。
ES6中的Promise
在可能發(fā)生等待的情況
等待過程中不能像alert一樣阻塞程序的時候
因此,所有的“等待的情況”都需要異步
一句話總結(jié)就是需要等待但是又不能阻塞程序的時候需要使用異步
千萬不要把異步和并行搞混了,
異步是單線程的,并行是多線程的
異步:主線程的任務(wù)以同步的方式執(zhí)行完畢,才會去依次執(zhí)行任務(wù)列隊中的異步任務(wù)
并行:兩個或多個事件鏈隨時間發(fā)展交替執(zhí)行,以至于從更高的層次來看,就像是同時在運(yùn)行(盡管在任意時刻只處理一個事件)
關(guān)于javascript異步的作用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。