這個問題來自某次講課某學長對我們的提問,課后記下了這個問題,在這里簡單的說一下自己的理解,有錯請幫忙指正~
學習web的同學都知道,javascript是一門單線程語言,單線程即代碼從上至下順序執(zhí)行。但是js還有一個特性是“異步”,很多人就會覺得這豈不是自相矛盾?其實不然。
所謂單線程,是指負責解釋并執(zhí)行JS代碼的線程只有一個,而真正在瀏覽器運行時還有其他很多線程,常見的有定時器線程(setTimeout/setInterval)及HTTP請求線程等。這三部分就是我們最常見的js異步。
關(guān)于JS異步問題,下面是高程(javascript高級程序設(shè)計)上的解釋:
除了主JavaScript執(zhí)行進程外,還需要一個在進程下一次空閑時執(zhí)行的代碼隊列。隨著頁面生命周期推移,代碼會按照執(zhí)行順序添加入隊列,例如當按鈕被按下的時候他的事件處理程序會被添加到隊列中,并在下一個可能時間內(nèi)執(zhí)行。
在接到某個Ajax響應(yīng)時,回調(diào)函數(shù)的代碼會被添加到隊列。JavaScript中沒有任何代碼是立即執(zhí)行的,但一旦進程空閑則盡快執(zhí)行。
定時器對隊列的工作方式是,當特定的時間過去后,將代碼插入,注意添加到隊列并不意味著它會馬上執(zhí)行,而只能說它會盡快執(zhí)行,設(shè)定一個150ms后執(zhí)行的定時器,不代表150ms后它會馬上執(zhí)行,它只會表示在150ms后被加入到隊列中,如果這個時間點隊列是空閑的,那么這段代碼就會被執(zhí)行;其他情況下,代碼可能明顯地等待更長時間才執(zhí)行。
只看完這么一大段文字可能的確有些暈乎,那我們來一點點分析~
下面來一個小例子,請問輸出的順序應(yīng)該是什么呢?
<script type="text/javascript">
console.log(1);
setTimeout(function(){
console.log(2);
},0); //注意這里間隔0秒
console.log(3);
</script>
如果單單以單線程的思路去想,代碼肯定是自上至下的順序執(zhí)行,那么輸出順序必然是:1,2,3.但是這段代碼實際的執(zhí)行結(jié)果是按順序輸出:1,3,2.這是為什么?
我來總的細說一下:
(1).JS是單線程的沒錯,意思是指瀏覽器運行過程中用來解釋運行js程序的過程是一個單線程的過程。
(2).瀏覽器是多線程的,這些線程在內(nèi)核控制下相互配合以保持同步:js線程,定時器線程,HTTP請求線程。。。之類
(3).當js代碼執(zhí)行時,如果遇到定時器函數(shù)或者Ajax請求時,這就是其他線程的事情啦!定時器線程和HTTP請求線程都各自異步的執(zhí)行完這一份的事件后,把
回調(diào)函數(shù)返回給了js線程中的任務(wù)隊列的最后!!也就是說這些回調(diào)函數(shù)不一定是立即執(zhí)行,只有在js線程中的所有任務(wù)都執(zhí)行完之后才會調(diào)用這些回調(diào)。所以剛才的代碼輸出順序是: 1,3,2.
可以參考這篇博客中的圖來理解一下 [1]看過一個畫得很詳細的圖
我的想法大概就是這些,3Q~ 感謝閱讀