我最近遇到了一个相当严重的错误,其中代码通过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()?


当前回答

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

其他回答

在问题中,存在以下之间的竞争条件:

浏览器尝试初始化下拉列表,准备更新其选择的索引 设置所选索引的代码

您的代码总是在这场竞赛中胜出,并试图在浏览器准备好之前设置下拉选择,这意味着会出现错误。

这种竞争的存在是因为JavaScript有一个与页面呈现共享的执行线程。实际上,运行JavaScript会阻塞DOM的更新。

你的解决方案是:

setTimeout(callback, 0)

使用回调调用setTimeout,并将0作为第二个参数,将在尽可能短的延迟之后调度回调异步运行——当选项卡有焦点且JavaScript执行线程不忙时,大约为10ms。

因此,OP的解决方案是将所选索引的设置延迟约10ms。这让浏览器有机会初始化DOM,修复bug。

每个版本的ie浏览器都表现出古怪的行为,这种变通方法有时是必要的。或者,它可能是OP代码库中的一个真正的错误。


请参阅Philip Roberts的“到底什么是事件循环?”以获得更详细的解释。

setTimout on 0在设置一个延迟承诺的模式中也非常有用,你想要立即返回:

myObject.prototype.myMethodDeferred = function() {
    var deferredObject = $.Deferred();
    var that = this;  // Because setTimeout won't work right with this
    setTimeout(function() { 
        return myMethodActualWork.call(that, deferredObject);
    }, 0);
    return deferredObject.promise();
}

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

通过调用setTimeout,您可以给页面时间来响应用户正在做的任何事情。这对于在页面加载期间运行的函数特别有用。

问题是您试图在一个不存在的元素上执行Javascript操作。元素还没有被加载,setTimeout()给了一个元素更多的时间,以以下方式加载:

setTimeout() causes the event to be ansynchronous therefore being executed after all the synchronous code, giving your element more time to load. Asynchronous callbacks like the callback in setTimeout() are placed in the event queue and put on the stack by the event loop after the stack of synchronous code is empty. The value 0 for ms as a second argument in function setTimeout() is often slightly higher (4-10ms depending on browser). This slightly higher time needed for executing the setTimeout() callbacks is caused by the amount of 'ticks' (where a tick is pushing a callback on the stack if stack is empty) of the event loop. Because of performance and battery life reasons the amount of ticks in the event loop are restricted to a certain amount less than 1000 times per second.