本篇文章帶給大家的內容是關於javascript異步是什麼?有什麼用?有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
我們知道JavaScript的單執行緒的,這與它的用途有關。作為瀏覽器腳本語言,JavaScript的主要用途是與使用者互動,以及操作DOM。這決定了它只能是單線程,否則會帶來複雜的同步問題。例如,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,而這時瀏覽器應該以哪個線程為準?
所謂"單線程",就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務,以此類推。
這種模式的好處是實現起來比較簡單,執行環境相對單純;壞處是只要有一個任務耗時很長,後面的任務都必須排隊等著,會拖延整個程式的執行。常見的瀏覽器無回應(假死),往往是因為某一段Javascript程式碼長時間運作(例如死循環),導致整個頁面卡在這個地方,其他任務無法執行。
ajax的同步請求就會導致瀏覽器產生假死,因為它會鎖定瀏覽器的UI(按鈕,菜單,滾動條等),並阻塞所有用戶的交互,jquery中的ajax有這樣一個同步請求的功能,一定要慎用,尤其是在請求的資料量很大的時候,要避免使用同步請求。
舉幾個栗子感受一下非同步
後台介面使用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);
輸出,應該沒什麼懸念
//null //null //定时器
執行順序:
先執行第一個console.log(myData);
然後遇到了定時器,將定時器掛起(就是暫停了這個定時器)
繼續執行第二個console.log(myData);
沒有可以執行的js程式碼,回頭把掛起的任務繼續執行下去
繼續看下一個栗子
console.log(myData); ajax() console.log(myData);
看下輸出,依然沒有懸念
//null //null //ajax返回成功 //{success: true, data: {…}}(这是接口返回的数据,我们不必关心返回的具体内容,只要知道返回了就好,陌上寒注)
執行順序和上面的定時器基本上類似,不在此贅述。
將兩個栗子合併,我們看下
console.log(myData); ajax() setTimeout(() => { console.log('定时器'); }, 2000); console.log(myData);
輸出,
//null //null //ajax返回成功 //{success: true, data: {…}} //定时器
發現問題了嗎?兩個非同步函數相遇了,先執行誰?誰跑的快就先執行誰?
也可以這麼說,其實這引發了另外一個知識點,
兩個 console.log(myData);是同步執行的,他們都在js的主執行緒上執行,
在主執行緒之外還存在一個任務佇列,任務佇列中存放著需要非同步執行的內容
當主執行緒運行完畢之後,就會去執行任務佇列中的任務(不斷的重複掃描)直到任務佇列清空
觀察這段程式碼
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);在主執行緒中,先執行,
setTimeout(function(){console.log(1);}, 0);放在了任務佇列中,
只有在主執行緒執行完了才會去執行任務列隊中的內容
看這段程式碼,有助於你的理解
console.log(myData); ajax() setTimeout(() => { console.log('定时器'); }, 2000); console.log(myData); const btn = document.querySelector('button') btn.onclick = () => { console.log("点击了"); }
我們為button按鈕添加了點擊事件,在瀏覽器刷新的同時不停地對按鈕進行點擊操作(當然是手動點擊)
看下輸出:
//null //null //(10次输出)点击了 //ajax返回成功 //{success: true, data: {…}} //定时器 //点击了
這樣是不是可以理解為什麼主執行緒要去循環掃描任務列隊了?
事件循環的每一輪稱為一個tick(有沒有聯想到vue中的nextTick?)
當產生用戶互動(滑鼠點擊事件,頁面滾動事件,視窗大小變化事件等等),ajax,定時器,計時器等,會在事件循環中的任務佇列新增事件,然後等待執行,
定時任務:setTimeout,setInverval
#網路請求:ajax請求,img圖片的動態載入
#事件綁定或叫DOM事件,例如一個點擊事件,我不知道它什麼時候點,但是在它點擊之前,我該做什麼還是做什麼。用addEventListener註冊類型的事件的時候,瀏覽器會有一個單獨的模組去接收這個東西,當事件被觸發的時候,瀏覽器的某個模組,會把對應的函數丟到非同步佇列中,如果現在執行棧中是空的,就會直接執行這個函數。
ES6中的Promise
在可能發生等待的情況
等待過程中不能像alert一樣阻塞程式的時候
因此,所有的「等待的情況」都需要非同步
一句話總結就是需要等待但是又不能阻塞程式的時候需要使用非同步
千萬不要把非同步和並行搞混了,
非同步是單執行緒的,並行是多執行緒的
非同步:主執行緒的任務以同步的方式執行完畢,才會去依序執行任務列隊中的非同步任務
並行:兩個或多個事件鏈隨時間發展交替執行,以至於從更高的層次來看,就像是同時在運行(儘管在任意時刻只處理一個事件)
以上是javascript異步是什麼?有什麼用?的詳細內容。更多資訊請關注PHP中文網其他相關文章!