作者senser (彷彿曾經一起死過)
看板Ajax
標題Re: [討論] javascript是共時、多執行緒嗎?
時間Mon Nov 7 18:19:35 2011
看來大家對這個問題都相當有興趣
我試著虐待一下我的FF 看看能不能證明有沒有multi-thread
(說真的opera說有 我也不確定 說不定他在騙我們XD)
為了測試
首先 你要在你的url打 about:config
搜尋 extensions.firebug.console.logLimit
然後把他調成十萬之類的
接著開一個空白文件叫做"thread.html"
然後貼上:
<html>
<head></head>
<body>
<iframe style="width:200px;height:200px" src='thread.html?id=1' ></iframe>
<iframe style="width:200px;height:200px" src='thread.html?id=2'></iframe>
<iframe style="width:200px;height:200px" src='thread.html?id=3'></iframe>
<iframe style="width:200px;height:200px" src='thread.html?id=4'></iframe>
<iframe style="width:200px;height:200px" src='thread.html?id=5'></iframe>
<script type="text/javascript"
src="
http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script>
var MultiThread = {
start : function(){
if(location.href.indexOf("?") == -1) return;
this.stopRecursion();
this.id = this.getID();
this.doManyLog();
//this.doLogForever();
},
doLogForever : function() {
while(1)
console.log(this.id);
},
doManyLog : function(){
for(var i = 0,count = 3000 ; i < count ; i++){
console.log(this.id);
};
},
getID : function(){
return location.href.split('=')[1];
},
stopRecursion: function() {
$('iframe').each(function(){
$(this).attr('src','');
});
}
};
$(function() {
MultiThread.start();
})
</script>
</body>
=============================
這段code基本上就是利用網址的變化去知道是哪個iframe
如果有multi-thread 迴圈會被中斷 被其他的iframe插隊
在數字不夠多的情況下 你會看到12345一段一段按順序跑完
但是加多一點像是3000時 你就會發現 每一個迴圈會被插隊
然後交互著跑 我想這應該是multi-thread的特性
另一個怪招是
如果你真的怒了 給他加到十萬或是無限迴圈之類的
你會發現你的FF投降時 會問你這一段script太久了 要不要中斷
然後這個視窗不只一個 每個iframe裡的script都會問你
我想這意味著 每個iframe都執行script了
而在第一個沒跑完的情況下 其他也執行到了 代表有插隊情況
所以這可能也代表著不只一個 thread
所以我想 大概是有multi-thread
※ 引述《senser (彷彿曾經一起死過)》之銘言:
: alert在不同thread下(iframe)到底會怎樣我倒是沒有研究過
: 我把您的code改成
: var $ = function(id){return document.getElementById(id);};
: $('ifa').src = 'javascript:alert("A");alert("B")';
: $('ifb').src = 'javascript:alert("C");alert("D")';
: 我剛剛試的結果
: 意外發現FF下會先出現A(很快來不急按) 然後被C蓋住 之後D 回到A 最後B
: 這有點兩個alert一起出現的味道(只是被蓋住了)
: IE的結果就是同一時間只有一個alert 然後ABCD
: 這跟browser的實作有關
: 我只能推斷 FF的alert出現時 容許其他的thread的alert也出現
: (不確定是 出現兩個 一個被"蓋住" 或是同一個alert box然後內容被取代
: 在我的FF中沒辦法用滑鼠移動alert box)
: 而IE的UI不容許這種情況出現
: 然後回到問題
: 在兩個thread併行下 ACBD交叉出現我覺得是有可能的
: (但我不知道哪個browser可以 也沒試著去製造出來過)
: 但是在一個event-driven 的single thread中(前篇文章) 是不會發生的
: 一個callback只會執行完在去執行下一個 不會互相跳來跳去
: ==============
: 各家瀏覽器對alert的實作略有不同
: 一般當alert出現時 產生alert那段程式會暫停 直到按了之後在繼續
: 然而有些瀏覽器在alert出現時 會繼續dispatch的動作
: dispatch進去的handler中 如果是UI trigger的 他不會執行
: 但如果是non-UI 的event handler 像是ajax的callback
: 在某些browser中是會同時執行的 即使你的alert還掛在那裏
: 所以用alert debug的習慣是非常不好的
: 在你還沒按下時 可能有東西就跑起來了
: 以致於你alert出來的變數也有可能被影響 而看到錯的值
: 真的用在application中更是有可能造成錯誤 (confirm,prompt等等都一樣)
: 根據你甚麼時候按下去 你的那段程式才會繼續跑
: 但是你的non-UI event在背後一樣的dispatch然後fire (如page load,timeout)
: 所以希望大家改掉直接用這種東西當UI的習慣 避免不必要的timing issue
: 全部的UI都要自己兜出來比較好
: ===
: 這裡就有現成的例子
: 剛剛用FF看 好像是CDAB (按掉CD時A或若隱若現)
: 如果你沒有注意那個若隱若現的A 你就會以為他的順序真的是CDAB這樣
: 然而如果你改成console.log("A")
: 就會知道他的真正的順序是ABCD
: 給大家參考:D
: ※ 引述《senser (彷彿曾經一起死過)》之銘言:
: : 跟大家分享一下 我對一般常見的browser處理javascript的認知
: : 有錯誤請大家不吝指教
: : 先回答標題好了
: : 就我所知 目前javascript在browser的implementeation中
: : 在一個"window"下中只有一個thread 在這種情況下 你可以說javascript是單一thread
: : 事實上大部分的時候 我們只要以這出發點來考慮問題就足夠了
: : 然而 如果你的頁面中有iframe 他會有另外一個window去維護另一個thread
: : 在同網域下 他甚至可以存取相同的global物件 造成所謂的race condition
: : 在這種狀況下 你可以說javascript 是 multi-thread 我想也是合理的
: : =======================
: : 所以說 與其討論javascript到底是不是multi-thread
: : 其實應該討論的問題是 browser的實作方式
: : 首先我們開啟一個頁面 在這個window中會開啟一個thread 處理包括
: : 1.html的parse
: : 2.dispatching of events
: : 3.執行javascript
: : 然後在parse的過程中 如果遇到某些tag像是img, embed, iframe,object 等等
: : 他會開啟另外一個thread去下載,render,或是執行iframe裡面的js等等
: : 這也是為甚麼 我們會看到在load一個網頁 下載圖片是分開的 每張獨立下載 獨立顯示
: : 同時這種作法 也大大加速了我們顯示整個網頁的速度
: : 而這和我們的問題有甚麼關係呢?
: : 在我們前端開發人員的聖經"High Performance Web Sites"中提到
: : 我們應該盡量的把javascript放在網頁的下面
: : 為甚麼呢 因為在同一個window的single thread中 如果遇到<script>
: : html parsing的動作會停下來 直到
: : 1.下載 javascript(如果是外部連結的話)
: : 2.parse
: : 3.執行
: : 三個動作結束後 才會繼續往下
: : 如果這個javascript特別久 那下面網頁就久久不parse,整個page loading就卡在那裏
: : 所以呢 你應該已經猜到 在你load page時 不同<script>間的javascript執行一定是分開
: : 的
: : 只有一段<script>跑完 才有機會繼續往下parse HTML
: : 也才有機會遇到另外一個<script> 然後執行它
: : 而這個部分 我相信每個人都可以直觀的觀察到 這是single thread的感覺
: : 那為甚麼有人會提出這類的問題
: : 我想主要是因為javascript的一些feature如ajax,timer,alert...等等造成困惑
: : 要理解這些困惑 我們要先理解 javascript是怎麼被執行的
: : 以下有兩種狀況會執行js
: : 1.page load時立刻執行的js
: : 2.event handler
: : 第一種我們已經討論過了 很單純的由上往下 一個一個來
: : 第二腫 在js中我們都視為一種callback 當事件引發時 才會執行
: : 在browser對js的處理中 它maintain一個queue叫做 "Dispatch Sequence"
: : 當事件觸發時 會立刻把handler放到裡面(這動作叫作dispatch)
: : 然後根據先來後到的順序執行handler
: : 而在這過程中 當前一個handler沒跑完之前 下一個hander不會被執行
: : 所以說 js依然是single thread
: : timeout,或是ajax callback等等 我們都要視為是一個event 一樣是用這個規則在跑
: : 所以 timeout 5秒不一定會在5秒時跑 ajax callback也不一定會在respose 抵達時馬上
: : fire
: : 一切都要看 前面的handler執行完了沒 輪到他了沒
: : (題外話 alert 是個special case, 每個browser不太一樣 , 寫js的人要盡量少用)
: : 那最後回到我們的問題來
: : 那個alert ABCD會不會交叉出現呢 答案是不會 (alert要少用 像是sk1765的test case就
: : 非常好)
: : 相信你已經知道 在timeout中的function A B都是一個event handler(callback)
: : 在執行時 會結束才有可能去執行另一個 所以不會ABCD交叉出現
: : 最後我想說的是 js要看成是 event-driven的東西
: : 用thread去分析 就會陷入把他拆成一行一行看的陷阱
: : 而event-driven 產生的timing issue 對我來說 也是js bug中最難trace的一種
: : 文章寫的有點長 但其實還有很多細節
: : opera這篇文章寫得非常非常好 有興趣的各位可以參考看看
: : http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 71.107.60.113
※ 編輯: senser 來自: 71.107.60.113 (11/07 18:20)
1F:→ weiyucsie:那些iframe不知道可不可以動態生成就好?XD 11/07 18:49
2F:→ weiyucsie:感覺我的opera解讀成iframe裡面有iframe...XD 11/07 18:50
3F:→ weiyucsie:話說我把console.log(this.id); 11/07 19:06
4F:→ weiyucsie:改成document.body.innerHTML=++i; 11/07 19:07
5F:→ weiyucsie:每個iframe內的數字會一直增加算不算XD 11/07 19:07
6F:→ weiyucsie:雖然反應不好~ 11/07 19:07
7F:→ senser:我沒有opera耶 沒有試過 而ie大概會因為console而break 11/07 19:10
8F:→ senser:但是這個例子裡 的確是iframe裡面有iframe 11/07 19:10
10F:→ weiyucsie:iframe動態加上 以及改成document.body.innerHTML 11/07 19:29
11F:→ weiyucsie:不過這樣子看的話,又像是multi-thread...XD 11/07 19:29
12F:推 tyx:此例子是因為已經遞迴產生 nested iframe 11/07 19:30
13F:→ tyx:但 js 將 src="" 太慢 11/07 19:31
14F:→ tyx:所以有很多 iframe1 ifram2 ... 5 交叉執行 11/07 19:33
15F:→ tyx:並不是 multithread 造成的 11/07 19:35
16F:→ weiyucsie:剛開始的確會跑一些數字 fx看起來按繼續的時候 11/07 19:41
17F:→ weiyucsie:的確只有一個iframe會增加數字 11/07 19:41
18F:→ weiyucsie:而我用opera則是每個iframe的數字,隔一段時間都會增加 11/07 19:42
19F:→ tyx:我推測 opera 可能是 user mode multithread 11/07 19:46
20F:→ weiyucsie:經過這幾篇文章 我也這麼猜測XD 11/07 19:48
21F:→ tyx:可能在 ; 之後安插自己的 sched_yield 11/07 19:49
22F:→ weiyucsie:這就不清楚了... 反正照文章所說的 setTimeout(...,0) 11/07 19:53
23F:→ weiyucsie:應該不會出問題才對~ 雖然我是想到 11/07 19:53
24F:→ weiyucsie:web worker是用postMessage 11/07 19:54
25F:→ tyx:存猜測 誰知到 opera 怎麼實作呢 XD 11/07 19:59
26F:→ tyx:我猜 FF 應該使用系統的 message queue 當成 11/07 20:00
27F:→ tyx:event handlers 的 event queue 11/07 20:00
28F:→ tyx:所以導致 event handler 重入 11/07 20:01
29F:→ weiyucsie:現在的js除了interpret還有jit... 懶得想太多XD 11/07 20:15
30F:→ weiyucsie:event handler重入 哪個現象? 11/07 20:16
31F:→ tyx:<script> 11/07 20:48
32F:→ tyx:var $ = function(id){return document.getElementById(id);}; 11/07 20:48
33F:→ tyx:</script> 11/07 20:48
34F:→ tyx:<iframe id=ifa></iframe> 11/07 20:48
35F:→ tyx:<iframe id=ifb></iframe> 11/07 20:48
36F:→ tyx:<script> 11/07 20:48
37F:→ tyx:$('ifa').src = 'javascript:alert("AAAAAAAAA ... 11/07 20:49
38F:→ tyx:很多 A 11/07 20:49
39F:→ tyx:;alert("B")'; 11/07 20:50
40F:→ tyx:$('ifb').src = 'javascript:alert("C");alert("D")'; 11/07 20:50
41F:→ tyx:可以看到重入現 11/07 20:51
42F:→ weiyucsie:實際跑了之後,終於知道是什麼意思了XD 11/07 21:43
43F:→ weiyucsie:AAA...的A夠多,使得alert box夠寬,可以同時看到兩個 11/07 21:43
44F:→ senser:第二層的iframe就清掉了網址 所以不會只會call自己一次 11/08 14:19
45F:→ senser:這樣寫只是寫成一個檔案方便 寫成多個檔案也是同樣結果摟 11/08 14:21
46F:→ tyx:你可以觀察 dom tree 其實不止兩層 11/08 23:49
47F:→ tyx:可以發現不只一個 thread.html?id=1 11/08 23:50
48F:→ tyx:所以才會不同數字交互出現 11/08 23:51
49F:→ tyx:那五個 iframe 獨立寫 裡面不要再有 iframe 11/08 23:52
50F:→ tyx:不同數字是不會交互出現的 11/08 23:53