Re: [討論] javascript是共時、多執行緒嗎?

看板Ajax作者 (彷彿曾經一起死過)時間13年前 (2011/11/07 18:19), 編輯推噓1(1049)
留言50則, 3人參與, 最新討論串9/11 (看更多)
看來大家對這個問題都相當有興趣 我試著虐待一下我的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="" rel="nofollow">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)

11/07 18:49, , 1F
那些iframe不知道可不可以動態生成就好?XD
11/07 18:49, 1F

11/07 18:50, , 2F
感覺我的opera解讀成iframe裡面有iframe...XD
11/07 18:50, 2F

11/07 19:06, , 3F
話說我把console.log(this.id);
11/07 19:06, 3F

11/07 19:07, , 4F
改成document.body.innerHTML=++i;
11/07 19:07, 4F

11/07 19:07, , 5F
每個iframe內的數字會一直增加算不算XD
11/07 19:07, 5F

11/07 19:07, , 6F
雖然反應不好~
11/07 19:07, 6F

11/07 19:10, , 7F
我沒有opera耶 沒有試過 而ie大概會因為console而break
11/07 19:10, 7F

11/07 19:10, , 8F
但是這個例子裡 的確是iframe裡面有iframe
11/07 19:10, 8F

11/07 19:28, , 9F
http://tinyurl.com/c85vz8e 我稍微修改的版本
11/07 19:28, 9F

11/07 19:29, , 10F
iframe動態加上 以及改成document.body.innerHTML
11/07 19:29, 10F

11/07 19:29, , 11F
不過這樣子看的話,又像是multi-thread...XD
11/07 19:29, 11F

11/07 19:30, , 12F
此例子是因為已經遞迴產生 nested iframe
11/07 19:30, 12F

11/07 19:31, , 13F
但 js 將 src="" 太慢
11/07 19:31, 13F

11/07 19:33, , 14F
所以有很多 iframe1 ifram2 ... 5 交叉執行
11/07 19:33, 14F

11/07 19:35, , 15F
並不是 multithread 造成的
11/07 19:35, 15F

11/07 19:41, , 16F
剛開始的確會跑一些數字 fx看起來按繼續的時候
11/07 19:41, 16F

11/07 19:41, , 17F
的確只有一個iframe會增加數字
11/07 19:41, 17F

11/07 19:42, , 18F
而我用opera則是每個iframe的數字,隔一段時間都會增加
11/07 19:42, 18F

11/07 19:46, , 19F
我推測 opera 可能是 user mode multithread
11/07 19:46, 19F

11/07 19:48, , 20F
經過這幾篇文章 我也這麼猜測XD
11/07 19:48, 20F

11/07 19:49, , 21F
可能在 ; 之後安插自己的 sched_yield
11/07 19:49, 21F

11/07 19:53, , 22F
這就不清楚了... 反正照文章所說的 setTimeout(...,0)
11/07 19:53, 22F

11/07 19:53, , 23F
應該不會出問題才對~ 雖然我是想到
11/07 19:53, 23F

11/07 19:54, , 24F
web worker是用postMessage
11/07 19:54, 24F

11/07 19:59, , 25F
存猜測 誰知到 opera 怎麼實作呢 XD
11/07 19:59, 25F

11/07 20:00, , 26F
我猜 FF 應該使用系統的 message queue 當成
11/07 20:00, 26F

11/07 20:00, , 27F
event handlers 的 event queue
11/07 20:00, 27F

11/07 20:01, , 28F
所以導致 event handler 重入
11/07 20:01, 28F

11/07 20:15, , 29F
現在的js除了interpret還有jit... 懶得想太多XD
11/07 20:15, 29F

11/07 20:16, , 30F
event handler重入 哪個現象?
11/07 20:16, 30F

11/07 20:48, , 31F
<script>
11/07 20:48, 31F

11/07 20:48, , 32F
var $ = function(id){return document.getElementById(id);};
11/07 20:48, 32F

11/07 20:48, , 33F
</script>
11/07 20:48, 33F

11/07 20:48, , 34F
<iframe id=ifa></iframe>
11/07 20:48, 34F

11/07 20:48, , 35F
<iframe id=ifb></iframe>
11/07 20:48, 35F

11/07 20:48, , 36F
<script>
11/07 20:48, 36F

11/07 20:49, , 37F
$('ifa').src = 'javascript:alert("AAAAAAAAA ...
11/07 20:49, 37F

11/07 20:49, , 38F
很多 A
11/07 20:49, 38F

11/07 20:50, , 39F
;alert("B")';
11/07 20:50, 39F

11/07 20:50, , 40F
$('ifb').src = 'javascript:alert("C");alert("D")';
11/07 20:50, 40F

11/07 20:51, , 41F
可以看到重入現
11/07 20:51, 41F

11/07 21:43, , 42F
實際跑了之後,終於知道是什麼意思了XD
11/07 21:43, 42F

11/07 21:43, , 43F
AAA...的A夠多,使得alert box夠寬,可以同時看到兩個
11/07 21:43, 43F

11/08 14:19, , 44F
第二層的iframe就清掉了網址 所以不會只會call自己一次
11/08 14:19, 44F

11/08 14:21, , 45F
這樣寫只是寫成一個檔案方便 寫成多個檔案也是同樣結果摟
11/08 14:21, 45F

11/08 23:49, , 46F
你可以觀察 dom tree 其實不止兩層
11/08 23:49, 46F

11/08 23:50, , 47F
可以發現不只一個 thread.html?id=1
11/08 23:50, 47F

11/08 23:51, , 48F
所以才會不同數字交互出現
11/08 23:51, 48F

11/08 23:52, , 49F
那五個 iframe 獨立寫 裡面不要再有 iframe
11/08 23:52, 49F

11/08 23:53, , 50F
不同數字是不會交互出現的
11/08 23:53, 50F
文章代碼(AID): #1Ejx2xsS (Ajax)
討論串 (同標題文章)
文章代碼(AID): #1Ejx2xsS (Ajax)