小编典典

为什么 setTimeout(fn, 0) 有时有用?

all

我最近遇到了一个相当讨厌的错误,其中代码是<select>通过 JavaScript 动态加载的。这个动态加载<select>的有一个预选值。在
IE6 中,我们已经有了修复 selected 的代码<option>,因为有时<select>‘ 的selectedIndex值会与
selected<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()


阅读 94

收藏
2022-02-28

共1个答案

小编典典

在问题中,存在以下竞争条件

  1. 浏览器尝试初始化下拉列表,准备更新其选定的索引,以及
  2. 您设置所选索引的代码

您的代码一直在赢得这场比赛,并试图在浏览器准备好之前设置下拉选择,这意味着会出现错误。

之所以存在这种竞争,是因为 JavaScript 有一个与页面渲染共享的执行线程。实际上,运行 JavaScript 会阻止 DOM 的更新。

您的解决方法是:

setTimeout(callback, 0)

Invoking setTimeoutwith a callback, and zero as the second argument will
schedule the callback to be run asynchronously , after the shortest
possible delay - which will be around 10ms when the tab has focus and the
JavaScript thread of execution is not busy.

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

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


参见 Philip Roberts 的演讲“事件循环到底是什么?”
以获得更详尽的解释。

2022-02-28