function a() { setTimeout(function(){alert(1)},0); alert(2); } a();
和其他的編程語言一樣,Javascript中的函數調用也是通過堆棧實現的。在執行函數a的時候,a先入棧,如果不給alert(1)加setTimeout,那么alert(1)第2個入棧,最后是alert(2)。但現在給alert(1)加上setTimeout后,alert(1)就被加入到了一個新的堆棧中等待,並”盡可能快“的執行。這個盡可能快就是指在a的堆棧完成后就立刻執行,因此實際的執行結果就是先alert(2),再alert(1)。在這里setTimeout實際上是讓alert(1)脫離了當前函數調用堆棧。
利用這一點,javascript實際上是有多個線程的。
問題是: 多個setTimeout 是 分別放在不同的堆棧嗎?如果是,那么我們就真的有了多線程的基礎了
另一篇文章中的闡述。哪個是對的呢?
javascript線程解釋(setTimeout,setInterval你不知道的事)
setTimeout( function(){ alert(’你好!’); } , 0); setInterval( callbackFunction , 100);
同理對setInterval的callbackFunction方法每間隔100毫秒就立即被執行深信不疑!
div.onclick = function(){ setTimeout( function(){document.getElementById(’inputField’).focus();}, 0); };
setTimeout( function(){ while(true){} } , 100); setTimeout( function(){ alert(’你好!’); } , 200); setInterval( callbackFunction , 200);
JavaScript引擎是單線程運行的,瀏覽器無論在什么時候都有且只有一個線程在運行JavaScript程序.
JavaScript引擎用單線程運行也是有意義的,單線程不必理會線程同步這些復雜的問題,問題得到簡化
那么單線程的JavaScript引擎是怎么配合瀏覽器內核處理這些定時器和響應瀏覽器事件的呢?下面結合瀏覽器內核處理方式簡單說明
瀏覽器內核實現允許多個線程異步執行,這些線程在內核制控下相互配合以保持同步。假如某一瀏覽器內核的實現至少有三個常駐線程:javascript引擎線程,界面渲染線程,瀏覽器事件觸發線程,除些以外,也有一些執行完就終止的線程,如Http請求線程,這些異步線程都會產生不同的異步事件,下面通過一個圖來闡明單線程的JavaScript引擎與另外那些線程是怎樣互動通信的,雖然每個瀏覽器內核實現細節不同,但這其中的調用原理都是大同小異
所以,在腳本中執行對界面進行更新操作,如添加結點,刪除結點或改變結點的外觀等更新並不會立即體現出來,這些操作將保存在一個隊列中,待JavaScript引擎空閑時才有機會渲染出來。
同理,還是在t1時間段內,接下來某個setInterval定時器也被添加了,由於是間隔定時,在t1段內連續被觸發了兩次,這兩個事件被排到隊尾等待處理。
如果隊列非空,引擎就從隊列頭取出一個任務,直到該任務處理完,即返回后引擎接着運行下一個任務,在任務沒返回前隊列中的其它任務是沒法被執行的.
相信您現在已經很清楚JavaScript是否可多線程,也理解JavaScript定時器運行機制了,下面我們來對一些案例進行分析:
案例1:setTimeout與setInterval
setTimeout(function(){ /* 代碼塊... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /*代碼塊... */ }, 10);
這兩段代碼看一起效果一樣,其實非也
第一段中回調函數內的setTimeout是JavaScript引擎執行后再設置新的setTimeout 定時(此時會把代碼插入任務隊列),假定上一個回調處理完到下一個回調開始處理為一個時間間隔,理論兩個setTimeout回調執行時間間隔>=10ms。setTimeout好處就是嚴格保證每隔一段時間執行代碼。
第二段自setInterval設置定時后,定時觸發線程就會源源不斷的每隔十秒產生異步定時事件並放到任務隊列尾,理論上兩個setInterval 回調執行時間間隔<=10,這就可能導致上一段代碼執行完畢后立即執行下一段代碼,不會出現想象中的間隔一段時間再執行
其實請求確實是異步的,不過這請求是由瀏覽器新開一個線程請求(參見上圖),當請求的狀態變更時,如果先前已設置回調,這異步線程就產生狀態變更事件放到 JavaScript引擎的處理隊列中等待處理,當任務被處理時,JavaScript引擎始終是單線程運行回調函數,具體點即還是單線程運行 onreadystatechange所設置的函數.
setTimeout(function(a,b,c){ console.log(a);//a console.log(b);//b console.log(c);//c },0,3,4,5); setInterval(function(a,b,c){ console.log(a);//b console.log(b);//b console.log(c);//c },0,3,4,5);