3

我在 jQuery 上做了以下程序:

$(document).ready(function(){
    var k = 0;
    setTimeout(function(){alert("Hello")},500);
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
    }
});

我预计计时器事件将执行在循环执行期间提醒“Hello”字符串的函数。但是,它仅在循环完成后发生。

是语言特定的问题吗?在某些循环/执行中,我应该如何实现回调函数处理?

4

2 回答 2

10

你错过了 JavaScript 内部结构的一个关键特性:事件循环。所有函数都存储在那里并等待它们被执行。此外,JavaScript(通常——不包括 AJAX 和工作线程)是单线程的,所以在任何时候,只有一个函数被执行。

关于您的脚本:事件队列上的第一个函数是您的ready()回调。它被执行,同时在setTimeout()事件队列中放置许多其他函数(来自调用的回调)。但是为了执行这些,第一个函数必须完成,这意味着所有的循环都必须完成并且函数必须返回。

所以基本上会发生这种情况(每个要点中的第二行表示当前事件循环状态):

  1. 只是ready回调排队等待执行。

    ready()-回调

  2. setTimeout()回调被放置在事件队列中。

    ready()-回调 | setTimeout()-回调

  3. 所有的循环都完成了。

    ready()-回调 | setTimeout()-回调

  4. ready()回调已完成并从队列中删除。

    setTimeout()-回调

  5. 刚才setTimeout()回调被执行,你看到了你的alert()消息!

    setTimeout()-回调


因此,为了alert()在循环执行之间找到某个位置,您要么必须在第 2500 次迭代之后执行它:

$(document).ready(function(){
    var k = 0;
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
        if( i == 2500 ) {
          alert( 'Hello' );
        }
    }
});

或者将所有这些插入setTimeout()也放入回调中(如果您想访问外部,则需要某种关闭k):

$(document).ready(function(){
    var k = 0;
    setTimeout(function(){alert("Hello")},500);
    for (var i = 0; i < 5000; ++i) {
        ++k;
        setTimeout( (function( k ) { 
          $('.inner').append('<p>Test</p>' + k.toString());
        })( k ), 0 );
    }
});
于 2013-05-26T08:42:14.247 回答
1

是的,是语言问题。JavaScript 中的 setTimeout 在指定的毫秒数执行代码,在您的情况下为 500。它将脚本排队并继续执行下一行代码,因此您的循环被执行,而线程将等待 500 毫秒来执行您的警报。

如果您希望 for 循环在 500 毫秒后运行,请执行此操作

setTimeout(function(){
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
    }
},500);
于 2013-05-26T08:45:20.410 回答