JS的運行機制

代碼塊: JS中的代碼塊是指由<script>標籤分割的代碼段。JS是按照代碼塊來進行編譯和執行的,代碼塊間相互獨立(即就算代碼塊1出錯,但不影響代碼塊2的加載和執行),但變量和方法共享。
案例:2個代碼塊
<script type="text/javascript">
    console.log("這是代碼塊一");
</script>
 
<script type="text/javascript">
    console.log ("這是代碼塊二");
</script>
 
 
HTML頁面中JS的加載原理: 在加載HTML頁面的時候,當瀏覽器遇到內嵌的JS代碼時會中止處理頁面,先執行JS代碼,而後再繼續解析和渲染頁面。一樣的狀況也發生在外鏈的JS文件中,瀏覽器必須先花時間下載外鏈文件中的代碼,而後解析並執行它,在這個過程當中,頁面的渲染和用戶互交徹底被阻塞。因爲現代瀏覽器都容許並行下載JS文件,所以<script>標籤在下載外部資源時不會阻塞其餘的<script>標籤。遺憾的是JS下載過程仍然會阻塞其餘資源的下載。
 
JavaScript的單線程:
JS語言的一大特色就是單線程,也就是說,同一個時間只能作一件事情。之因此是單線程,是由於與它的用途有關,做爲瀏覽器腳本語言,JS的主要用途是與用戶互動以及操做DOM。這決定了它只能是單線程,不然會帶來複雜的同步問題。爲了利用多核CPU的計算功能,HTML5提出了web worker標準,容許JS腳本建立多個線程,可是子線程徹底受主線程控制,且不能操做DOM,因此這個新標準並無改變JS單線程的本質。
 
JavaScript的任務列隊:
JS任務能夠分爲兩種: 一種是同步任務,另外一種是異步任務。注意,只有主線程空了,纔會去讀取"任務隊列",這就是JS的運行機制,這個過程會不斷重複。
同步任務: 在主線程上排隊執行的任務,只有前一個任務執行完畢了,纔會執行後一個任務
異步任務: 在主線程以外,還存在一個「任務列隊」,異步任務就是不進入主線程,而是進入「任務列隊」的任務,只有「任務列隊」通知主線程,某個異步任務能夠執行了而且同步任務執行完畢,該任務纔會進入主線程執行。
 
Javascript的事件和回調函數:
"任務列隊"是一個事件的列隊,IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務能夠進入"執行棧"了。主線程讀取"任務隊列",就是讀取裏面有哪些事件。"任務隊列"中的事件,除了IO設備的事件之外,還包括一些用戶產生的事件(如鼠標點擊、頁面滾動等等)。只要指定過回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。所謂"回調函數",就是那些會被主線程掛起的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。"任務隊列"是個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動進入主線程。可是,因爲存在後文提到的"定時器"功能,主線程首先檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。
 
定時器:
除了放置異步任務的事件,"任務隊列"還能夠放置定時事件,即指定某些代碼在多少時間以後執行。定時器功能主要由setTimeout()和setInterval()這兩個函數來完成,它們的內部運行機制徹底同樣,區別在於前者指定的代碼是一次性執行,後者則爲反覆執行。如下主要討論setTimeou()方法:
setTimeout()接受兩個參數,第一個是回調函數,第二個是推遲執行的毫秒數     
console.log(1)
setTimeout(function (){
     console.log(2)
}, 1000);
console.log(3)
上面代碼的執行結果是1=>3=>2,由於setTimeout()將第二行推遲到1000毫秒以後執行
 
若是將setTimeout()的第二個參數設爲0,就表示當前代碼執行完(執行棧清空)之後當即執行
setTimeout(function (){
     console.log(2)
}, 0);
console.log(3)
上面代碼的執行結果是3=>2,由於只有在執行完第二行之後,系統纔會去執行"任務隊列"中的回調函數。總之,setTimeout(fn, 0)的含義是,指定某個任務在主線程最先的空閒時間執行,也就是說盡量早的執行。它在"任務隊列"的尾部添加一個事件,所以要等到同步任務和"任務隊列"現有的事情都處理完,纔會獲得執行。
 
須要注意的是,setTimeout()知識將事件插入了"任務隊列",必須等到當前代碼(執行棧)執行完,主線程纔會去執行它指定的回調函數,要是當前代碼耗時很長,有可能要等好久,因此並無辦法保證回調函數必定會在setTimeout()指定的時間執行。
相關文章
相關標籤/搜索