从代码生成的INPUT元素中选择文件后,不会触发事件onChange

Wh1*_*Ck5 9 javascript onchange

我正在玩JavaScript并编写简单的函数来创建INPUTelement(type="file")并模拟点击.

var createAndCallFileSelect = function () {
    var input = document.createElement ("input");
    input.setAttribute ("type", "file");
    input.addEventListener ("change", function () {
        console.log (this.files);
    }, false);
    input.click();
}
Run Code Online (Sandbox Code Playgroud)

它大部分时间都很有效,但有时它不会onChange在选择文件时触发事件(或者在使用multiple属性时使用更多文件INPUT).

我知道onChange当你重新选择同一个文件时不会触发,但很明显这不是这里的情况.它仅在我第一次使用此功能时才触发事件,有时仅触发.onChange如果从对话框中选择了某些内容,则每次下一次点击通

已经尝试在这里和周围寻找这个问题,但似乎所有onChange问​​题和解决方案都与重新选择相同文件的着名问题有关.

我发现这种情况发生在最新的Opera和Firefox上,从未在其他浏览器上测试过.也.我试图等待整个页面加载,但结果仍然相同 - 有时它不会onChange在第一次调用时触发.

任何人都可以向我解释为什么会这样吗?我已经有了解决方法代码,这不是问题,只需要解释为什么在创建INPUT并以这种方式调用时会发生这种情况.

更新:

级联延迟

var function createAndCallFileSelect = function () {
    var input = document.createElement ("input");
    setTimeout (function () { // set type with 1s delay
        input.setAttribute ("type", "file");
        setTimeout (function () {  // attach event with 1s delay
            input.addEventListener ("change", function () {
                console.log (this.files);
            }, false);
            setTimeout (function () { // simulate click with 1s delay
                input.click();
            }, 1000);
        }, 1000);
    }, 1000);
}
Run Code Online (Sandbox Code Playgroud)

这也行不通.我试图延迟每一行的执行,以确保一切都以正确的顺序执行.调用后3秒打开文件选择对话框,但有时它会onChange在选择文件后触发事件.

Mik*_* S. 5

这是一个竞争条件。这取决于堆栈中的内容以及在调用同步文件浏览器阻止堆栈的其余部分完成之前某些事情可能需要多长时间。使用 addeventlistener,它将回调排队供以后使用,当堆栈清除时,事件循环将拾取该回调。如果堆栈没有及时清空,则不会被及时调用。无法保证什么时候会运行。如果您按照 Pawel 的建议使用 setTimeout(fn, 0),您将在放置事件侦听器后将要调用的 click() 函数排队。

这是一个很棒的视频,可以将我所说的一切可视化:https : //www.youtube.com/watch?v=8aGhZQkoFbQ

更新: 在进一步研究之后,我注意到 chrome 有一些非常有趣的事情......它一次最多只允许创建 5 个这些元素。我这样做了:

for(var i = 0; i < 20; i += 1) {
    createAndCallFileSelect()
}
Run Code Online (Sandbox Code Playgroud)

在那里有几个不同的数字......每次,任何大于 5 的数字只产生 5 个带有 5 个回调的输入元素,而 5 及以下产生正确的数量。

我也递归地尝试过这个,而不是使用 for 循环......结果相同。

此外,我选择的文件越大,所需的时间就越长,但最终它会在处理文件后调用回调。到目前为止,这项测试都是在 chrome 中进行的。