【问题标题】:JavaScript DOM Render OnLoadStart and OnLoad Function Running At The Same TimeJavaScript DOM 渲染 OnLoadStart 和 OnLoad 函数同时运行
【发布时间】:2021-09-27 03:06:20
【问题描述】:

问题

当单击导入按钮时,下面的 JavaScript onloadstart 函数将运行并显示警报/日志,但是在该警报上单击确定后,也会显示完成加载警报。 5 秒后文件实际完成并填充文本框。

为什么开始和结束的警报/日志都在开始时运行?我希望在实际填充文本框时运行完成的警报,这仅在文件真正导入后才会发生。

编辑

也许导入已完成,但文本框填充需要 5 秒钟。

现在的问题是如何在渲染完成后触发完成事件。

我对页面刷新感到好奇,我在页面顶部的网站上添加了下面的 Fiddle。单击导入后,“tick”值会停止刷新约 5 秒钟,然后恢复。一旦恢复,文本框也会被填充。似乎整个页面刷新在文本框 DOM 渲染期间停止。

https://jsfiddle.net/mosdxrhk/

JSON 文件大小:6 mb

导入 JSON 文件后 textarea 的字符数

document.getElementById('importTextArea').value.length

8,014,573

我还注意到,在我对该文本区域执行一些操作并将其输出到另一个文本区域后,新文件字符数为 3700 万。这最终会导致整个 Chrome 网页崩溃。

HTML

<textarea class="form-control" spellcheck="false" id="importTextArea"></textarea>

JavaScript

    document.getElementById('import').onclick = function() {
        var files = document.getElementById('selectFiles').files;
        console.log(files);
        if (files.length <= 0) {
            return false;
        }
        
        var fr = new FileReader();
        fr.onloadstart = function(e) {
            console.log("start loading");
            alert("start loading");
        }
        fr.onload = function(e) { 
            console.log(e);
            var result = JSON.parse(e.target.result);
            var formatted = JSON.stringify(result, null, 2);
            document.getElementById('importTextArea').value = formatted; // populated text box
            console.log("finished loading");            
            alert("finished loading");
        }
        fr.readAsText(files.item(0));
    };

【问题讨论】:

  • alert 调用替换为console.log 调用有何不同?
  • @traktor 对问题进行了编辑。警报与日志没有区别。此外,我不确定 onload 是在寻找文件上传完成还是整个功能完成。无论哪种方式,我都希望在文本框完成时显示警报/日志,这意味着上传、计算和文本框填充需要完成,然后触发警报/日志。
  • "可能导入完成,但文本框填充需要 5 秒。"是的,这将是最合乎逻辑的解释。你的 JSON 文件有多大?在处理和呈现整个文本后,您应该能够通过在onload 事件处理程序中执行requestAnimationFrame(() =&gt; setTimeout(yourCallback)) 来触发任务(其中yourCallback 将是您要执行的函数)。
  • @Kaiido 原来是这个问题,您有任何示例可能适合上面在requestAnimationFrame 上发布的代码吗?

标签: javascript filereader


【解决方案1】:

是的,这是异步渲染。

使用下面的示例,没有任何FileReader,我设法在 Chromium 中重现了效果。修改 DOM 并不会立即重新渲染页面:它只会安排近期的渲染周期。而 Firefox 则不这样:当 textarea DOM 节点被修改时,浏览器执行一个完整的渲染周期,然后才显示警报。

function populate() {
    var rep = parseFloat(document.getElementById('rep').value);
    document.getElementById('a').value = 'a'.repeat(rep);
    alert('hi');
}
<textarea id="a"></textarea><br>
repetitions: <input id="rep" type="number" value="5e6"><br>
<button onclick="populate()">populate</button>

【讨论】:

  • “浏览器执行一个完整的渲染周期”,不,他们执行一种“spin the event loop”,所以在这个浏览器中,渲染引擎只会在显示模式时继续工作,即使用户脚本被阻止(Chrome 对debugger 做了类似的事情)。但这并不能证明 OP 确实会发生这种情况,他们表示他们将在关闭模式后 5 秒内进行渲染。
  • 嗯,在不同的 DOM 引擎中确切发生的事情会随着每个版本的发布而改变。我很欣赏 user3840170 解释异步渲染背后的基本原理的方式,即使它在某些“细节”中可能是“不正确的”。
  • @CarstenMassmann 他们在回答中所说的内容对您来说很有趣(即使是错误的......)并不意味着这是对手头问题的一个很好的回答。如果没有来自 OP 的更多信息,我们无法断言是什么导致了他们的经历。
  • 我认为最重要的一点是:(a) 调用alert 并不能保证页面会重新呈现,并且(b) 这与FileReader 无关。布局引擎如何实现的实际细节在这里相对不重要。
  • @user3840170 您最后的评论是正确的,这最终成为渲染的问题。您发布的 sn-p 是我正在经历的。我会相应地更新问题。此外,我仍然需要找到一种方法在渲染完成后发布通知。