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

看板Ajax作者 (?????????????????)時間12年前 (2011/11/07 03:39), 編輯推噓2(202)
留言4則, 3人參與, 最新討論串5/11 (看更多)
在同一個 page 裡 只有一個 thread 在執行 不管有幾個 iframe 都一樣 (但 Opera 不是 推文有連結) 那為何有不同的行為 我以 senser 的範例作說明 1. FireFox 當 FF 執行 $('ifa').src = 'javascript:alert("A");alert("B")'; 時 會先 parse 這段 javascript 但並不會立刻執行此 js 而是產生一個 '要執行此 js 的 event'(暫時稱為 event1) 在 event queue 裡 之後執行下一行 $('ifb').src = ... 並產生 event2 然後 thread 回去 event queue 取到 event1 並執行 alert("A") 此時會看到 alert("A") 的 dialog 此 dialog 出現時 除了此 dialog 以外 page 的 input 都會被 disabled 所以不會有其他 UI events 當 alert("A") dialog 執行時 內部也有個 event loop 在取 event 出來執行 所以會取到 event2 並執行 alert("C") 當你按掉 alert("C") 之後 會立刻執行 alert("D") 再按掉 alert("D") 又會回到 alert("A") 的內部 event loop 再按掉 alert("A") 之後 會執行 alert("B") 所以會看到 alert("A") 出現後 立刻出現 alert("C") 然後結束 alert("C") 立刻出現 alert("D") 然後結束 alert("D") 回到 alert("A") 然後結束 alert("A") 立刻出現 alert("B") 2. IE 當 IE parse 完 js 之後會立刻執行 所以才會 出現 A 按掉A之後出現 B 按掉 B 之後出現 C 按掉 C 之後出現 D ps: 至於 console.log("A") 會依序出現 是因為執行 console.log("A") 時 並不會偷偷跑 event loop 所以 C D 不會偷跑囉 ※ 引述《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: 118.168.222.153

11/07 04:37, , 1F
In Opera,every window has its own JavaScript thread.
11/07 04:37, 1F

11/07 04:37, , 2F

11/07 11:31, , 3F
推詳解!
11/07 11:31, 3F
※ 編輯: tyx 來自: 114.32.33.99 (11/07 12:37)

11/07 14:07, , 4F
果然是高手
11/07 14:07, 4F
文章代碼(AID): #1EjkACd0 (Ajax)
討論串 (同標題文章)
文章代碼(AID): #1EjkACd0 (Ajax)