我最近遇到了一个相当严重的错误,其中代码通过JavaScript动态加载<select>。这个动态加载的<select>有一个预先选定的值。在IE6中,我们已经有代码来修复选中的<option>,因为有时<select>的selectedIndex值会与选中的<option>的index属性不同步,如下所示:

field.selectedIndex = element.index;

然而,这段代码没有工作。即使字段的selectedIndex设置正确,最终还是会选择错误的索引。但是,如果我在正确的时间插入alert()语句,则会选择正确的选项。考虑到这可能是某种时间问题,我尝试了一些以前在代码中见过的随机方法:

var wrapFn = (function() {
    var myField = field;
    var myElement = element;

    return function() {
        myField.selectedIndex = myElement.index;
    }
})();
setTimeout(wrapFn, 0);

这招奏效了!

我找到了解决问题的方法,但我不知道为什么这能解决我的问题,这让我感到不安。有人有官方解释吗?什么浏览器问题,我避免调用我的函数“稍后”使用setTimeout()?


当前回答

由于传递给它的持续时间为0,我认为这是为了从执行流中删除传递给setTimeout的代码。因此,如果它是一个可能需要一段时间的函数,它不会阻止后续代码的执行。

其他回答

这做的另一件事是将函数调用推到堆栈的底部,防止递归调用函数时堆栈溢出。这具有while循环的效果,但允许JavaScript引擎触发其他异步计时器。

Javascript是单线程应用程序,因此不允许同时运行函数,因此使用事件循环来实现此目标。setTimeout(fn, 0)所做的就是在调用栈为空时将它推入任务任务。我知道这个解释很无聊,所以我建议你看一下这个视频,这将帮助你在浏览器中如何工作。 看看这个视频:- https://www.youtube.com/watch?time_continue=392&v=8aGhZQkoFbQ

这是一个有老答案的老问题。我想重新审视这个问题,并回答为什么会发生这种情况,而不是为什么这种方法有用。

所以你有两个功能:

var f1 = function () {    
   setTimeout(function(){
      console.log("f1", "First function call...");
   }, 0);
};

var f2 = function () {
    console.log("f2", "Second call...");
};

然后按如下顺序调用它们f1();f2 ();看看第二个先执行。

原因如下:不可能让setTimeout的时间延迟为0毫秒。最小值由浏览器决定,不是0毫秒。历史上浏览器将这个最小值设置为10毫秒,但HTML5规范和现代浏览器将其设置为4毫秒。

如果嵌套级别大于5,并且超时时间小于4,则 将timeout增加为4。

同样来自mozilla:

要在现代浏览器中实现0毫秒超时,可以使用 window.postMessage()如下所述。

附注:信息是在阅读以下文章后获取的。

这里有相互矛盾的点赞答案,没有证据,就无法知道该相信谁。这里证明@DVK是正确的,@SalvadorDali是不正确的。后者声称:

这就是为什么:它不可能有一个时间setTimeout 延迟0毫秒。最小值由 而不是0毫秒。历史上浏览器会设置这个 至少10毫秒,但HTML5规格和现代浏览器 把它设置为4毫秒。”

4毫秒的最小超时与正在发生的事情无关。实际发生的情况是setTimeout将回调函数推到执行队列的末尾。如果在setTimeout(callback, 0)之后,阻塞代码需要几秒钟才能运行,那么回调将在几秒钟内不执行,直到阻塞代码完成。试试下面的代码:

function testSettimeout0 () {
    var startTime = new Date().getTime()
    console.log('setting timeout 0 callback at ' +sinceStart())
    setTimeout(function(){
        console.log('in timeout callback at ' +sinceStart())
    }, 0)
    console.log('starting blocking loop at ' +sinceStart())
    while (sinceStart() < 3000) {
        continue
    }
    console.log('blocking loop ended at ' +sinceStart())
    return // functions below
    function sinceStart () {
        return new Date().getTime() - startTime
    } // sinceStart
} // testSettimeout0

输出是:

setting timeout 0 callback at 0
starting blocking loop at 5
blocking loop ended at 3000
in timeout callback at 3033

看看John Resig关于JavaScript计时器如何工作的文章。当您设置超时时,它实际上会将异步代码排队,直到引擎执行当前调用堆栈为止。