作者tyx (?????????????????)
看板Ajax
标题Re: [讨论] javascript是共时、多执行绪吗?
时间Mon Nov 7 03:39:53 2011
在同一个 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
1F:→ weiyucsie:In Opera,every window has its own JavaScript thread. 11/07 04:37
3F:推 xxxx9659:推详解! 11/07 11:31
※ 编辑: tyx 来自: 114.32.33.99 (11/07 12:37)
4F:推 sk1765:果然是高手 11/07 14:07