0

我有 3 个这样调用的函数:

<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);
}

所以我期待以下内容:

  1. 它会写成“超时已开始!” 在页面加载后立即在页面上。
  2. 接下来会写“你好,我醒了!”;
  3. 然后在函数超时的循环中生成的日志会依次输出到控制台。但没有那种东西。实际上,首先出现的是函数 timeout() 中的循环。因此,我看到了所有这些日志消息,然后才页面上编写的函数 startIt() 和 mssTmt() 中收到消息。我必须承认这对我来说看起来很不寻常。为什么会有这样的顺序?我有一些假设,但当然最好从真正的 JS 大师那里得到准确的解释!请!

在RoryKoehein回答后更新我阅读了他通过链接给我的东西,但有些东西仍然难以理解。

我稍微改变了我的代码。现在有调用者:

function getStarted(){
    console.log(new Date().getTime()+' > getStarted() has been called');
  try{
    startIt();
    mssTmt();
timeout();
  }catch(e){
    alert(e.message);
  }
}

…</p>

<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()),有时在循环之后,取决于延迟值。

但最奇怪的是,即使延迟值相同,在所有这些尝试中,I/O 的顺序都变得不同了!例如:setTimeout(timeout,3); 有时它会导致首先在函数 startIt()、mssTmt() 中发生输出,有时反之亦然 - timeout()。老实说,我不知道这是什么意思……

4

1 回答 1

1

这很好地解释了它:http: //javascript.info/tutorial/events-and-timing-depth#javascript-execution-and-rendering

最重要的是:

在大多数浏览器中,渲染和 JavaScript 使用单个事件队列。这意味着当 JavaScript 运行时,不会进行渲染。

while 循环完全阻塞线程三秒钟。document.write 调用被添加到事件队列中,甚至可能被执行,但绘制事件发生在 JS 不再阻塞之后。

如果您打开 Chrome 的开发者工具时间线,您可以准确地看到浏览器在做什么(https://developers.google.com/chrome-developer-tools/docs/timeline)。

题外话:我假设这是测试代码。绝不应该在生产中使用这样的东西。在 body 标签 [1] 内内联堆叠多个函数,使用 document.write [2] 和阻塞 while 循环都是不好的做法 [3]。

1 window.onload vs <body onload=""/> 2为什么 document.write 被认为是“不好的做法”? 3 sleep() 的 JavaScript 版本是什么?

于 2013-08-25T21:29:41.483 回答