我有三个函数被这样调用:
<body onLoad="startIt(),mssTmt(),timeout()">
它们是:
function startIt(){
document.write('Timeout has started!');
}
function timeout(){
function sleep(milliSeconds) {
var startTime = new Date().getTime();
var cnt=0;
while (new Date().getTime() < startTime + milliSeconds){
cnt++;
if(cnt%1000000==0)
console.log('time expired: '+(new Date().getTime())+'<br>');
}
}
sleep(3000);
}
function mssTmt(){
var greeting = 'Hello, I am awake!';
document.write('<hr>'+greeting);
}
所以我期待以下内容:
- 它将写为"超时已开始!"页面加载后立即显示在页面上
- 接下来会写上"你好,我醒了!"
- 然后,在函数超时的循环中生成的日志将依次输出到控制台中。但没有那种。事实上,首先出现的是函数timeout()中的循环。因此,我看到了所有这些日志消息,只有在之后,我才能在页面上编写的函数startIt()和mssTmt()中获得消息。我必须承认这对我来说是不寻常的。为什么会有这样的序列?我有一些假设,但当然,从真正的JS大师那里得到确切的解释会更好!Plsss
在RoryKoehein回答后更新我读了他通过链接给我的东西,但有些东西仍然无法理解。
我稍微更改了一下代码。现在是来电者:
function getStarted(){
console.log(new Date().getTime()+' > getStarted() has been called');
try{
startIt();
mssTmt();
timeout();
}catch(e){
alert(e.message);
}
}
…
<a href="javascript:void();" onclick="getStarted();" id="getstarted">Get started!</a>
取而代之的是
<body onLoad="startIt(),mssTmt(),timeout()">
首先,会发生这样的事情:如果我在调用每个函数之前添加一个alert(),那么序列与代码中的序列完全相同——startIt()、mssTmt()、timeout()。所有实现都被阻止,直到我点击警报弹出窗口。请看插图。如果我删除警报,它的工作原理与前面一样(请参阅问题的起点)。那么,如果警报阻止了所有流程,为什么它会更改执行顺序(i/o)?接下来,当我试图通过setTimeout()调用函数timeout()时,我注意到了一个奇怪的脚本行为;此处:http://javascript.info/tutorial/events-and-timing-depth#the-settimeout-func-0-trick是这样写的setTimeout(..,0)技巧用于在堆叠事件之后执行代码,并修复与定时相关的问题。如果我这样修改代码:setTimeout(timeout,[delay]);它一直在不可预测地进行:
- 如果我将延迟设置为0,则它只在函数timeout()已完成
- 如果我增加延迟,有时它会输出(startIt(),mssTmt())BEFORE循环,有时在之后,取决于延迟值
但最奇怪的是,在所有这些尝试中,即使具有相同的延迟值,I/O的顺序也变得不同!例如:setTimeout(超时,3);有时它会导致函数startIt()、mssTmt()中的首次输出,有时反之亦然–timeout()。老实说,我不知道这是什么意思…
这很好地解释了这一点:http://javascript.info/tutorial/events-and-timing-depth#javascript-执行和呈现
最重要的是:
在大多数浏览器中,渲染和JavaScript使用单个事件队列。这意味着当JavaScript运行时,不会发生任何渲染。
while循环完全阻塞线程三秒钟。document.write调用被添加到事件队列中,甚至可能被执行,但绘制事件发生在JS不再阻塞之后。
如果你打开Chrome的开发者工具时间轴,你可以确切地看到浏览器在做什么(https://developers.google.com/chrome-developer-tools/docs/timeline)。
离题:我想这是测试代码。在任何情况下都不应该在生产中使用这样的东西。在body标记[1]中内联堆叠多个函数,使用document.write[2]和阻塞while循环都是不好的做法[3]。
1个窗口打开与<车身负载=">2为什么document.write被认为是";不良做法"?3 sleep()的JavaScript版本是什么?