gpt4 book ai didi

javascript - 长时间运行函数的 DOM 刷新

转载 作者:行者123 更新时间:2023-11-28 04:13:19 25 4
gpt4 key购买 nike

我有一个按钮,单击它时会运行长时间运行的函数。现在,当该函数运行时,我想更改按钮文本,但在某些浏览器(例如 Firefox、IE)中遇到问题。

html:

<button id="mybutt" class="buttonEnabled" onclick="longrunningfunction();"><span id="myspan">do some work</span></button>

JavaScript:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";

//long running task here

document.getElementById("myspan").innerHTML = "done";
}

现在这在 Firefox 和 IE 中出现问题,(在 chrome 中可以正常工作)

所以我想把它放入settimeout中:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";

setTimeout(function() {
//long running task here
document.getElementById("myspan").innerHTML = "done";
}, 0);
}

但这对 Firefox 也不起作用!按钮被禁用,颜色发生变化(由于应用了新的 css),但文本没有改变。

我必须将时间设置为 50 毫秒,而不是 0 毫秒,才能使其正常工作(更改按钮文本)。现在我至少发现这很愚蠢。我可以理解如果它只需要 0 毫秒的延迟就可以工作,但是在较慢的计算机中会发生什么?也许 Firefox 在设置超时时需要 100 毫秒?听起来很愚蠢。我试了很多次,1ms,10ms,20ms...不,它不会刷新它。只需 50 毫秒。

所以我遵循了本主题中的建议:

Forcing a DOM refresh in Internet explorer after javascript dom manipulation

所以我尝试了:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
var a = document.getElementById("mybutt").offsetTop; //force refresh

//long running task here

document.getElementById("myspan").innerHTML = "done";
}

但它不起作用(FIREFOX 21)。然后我尝试了:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";
var a = document.getElementById("mybutt").offsetTop; //force refresh
var b = document.getElementById("myspan").offsetTop; //force refresh
var c = document.getElementById("mybutt").clientHeight; //force refresh
var d = document.getElementById("myspan").clientHeight; //force refresh

setTimeout(function() {
//long running task here
document.getElementById("myspan").innerHTML = "done";
}, 0);
}

我什至尝试了 clientHeight 而不是 offsetTop 但什么也没有。 DOM 不会刷新。

有人可以提供可靠的解决方案(最好是非黑客的)吗?

提前致谢!

按照这里的建议我也尝试过

$('#parentOfElementToBeRedrawn').hide().show();

没用

Force DOM redraw/refresh on Chrome/Mac

TL;博士:

寻找一种可靠的跨浏览器方法来强制 DOM 刷新,而不使用 setTimeout(首选解决方案,因为根据长时间运行的代码类型、浏览器、计算机速度和 setTimeout 需要不同的时间间隔,setTimeout 需要 50 左右)至 100 毫秒,具体取决于情况)

jsfiddle:http://jsfiddle.net/WsmUh/5/

最佳答案

网页基于单线程 Controller 进行更新,一半的浏览器不会更新 DOM 或样式,直到 JS 执行停止,将计算控制权交还给浏览器。这意味着如果您设置一些 element.style.[...] = ...它不会启动,直到您的代码完成运行(要么完全运行,要么因为浏览器看到您正在做一些事情,让它拦截处理几毫秒)。

您有两个问题:1)您的按钮有 <span>在里面。删除它,只需在按钮本身上设置 .innerHTML 即可。但这当然不是真正的问题。 2)你正在运行很长的操作,你应该认真思考为什么,在回答为什么之后,如何:

如果您正在运行较长的计算作业,请将其切成超时回调(或者,在 2019 年,await/async - 请参阅本回答末尾的注释)。您的示例并没有显示您的“长期工作”实际上是什么(旋转循环不算在内),但根据您使用的浏览器,您有多种选择,有一个GIANT书注:不要在 JavaScript 中运行长时间的工作,就这样。根据规范,JavaScript 是单线程环境,因此您想要执行的任何操作都应该能够在几毫秒内完成。如果不能,那么您确实做错了什么。

如果您需要计算困难的事情,请使用 AJAX 操作将其卸载到服务器(跨浏览器通用,通常可以为您提供 a)更快的操作处理速度和 b)30 秒的时间,您可以异步地不-等待结果返回)或使用 webworker 后台线程(非常不通用)。

如果您的计算需要很长的时间,但并不荒谬,请重构您的代码,以便您执行部分操作,并有超时喘息空间:

function doLongCalculation(callbackFunction) {
var partialResult = {};
// part of the work, filling partialResult
setTimeout(function(){ doSecondBit(partialResult, callbackFunction); }, 10);
}

function doSecondBit(partialResult, callbackFunction) {
// more 'part of the work', filling partialResult
setTimeout(function(){ finishUp(partialResult, callbackFunction); }, 10);
}

function finishUp(partialResult, callbackFunction) {
var result;
// do last bits, forming final result
callbackFunction(result);
}

长计算几乎总是可以重构为几个步骤,要么因为您正在执行多个步骤,要么因为您运行相同的计算一百万次,并且可以将其分成批处理。如果你有(夸大)这一点:

var resuls = [];
for(var i=0; i<1000000; i++) {
// computation is performed here
if(...) results.push(...);
}

然后你可以简单地将其分割成一个带有回调的超时松弛函数

function runBatch(start, end, terminal, results, callback) {
var i;
for(var i=start; i<end; i++) {
// computation is performed here
if(...) results.push(...); }
if(i>=terminal) {
callback(results);
} else {
var inc = end-start;
setTimeout(function() {
runBatch(start+inc, end+inc, terminal, results, callback);
},10);
}
}

function dealWithResults(results) {
...
}

function doLongComputation() {
runBatch(0,1000,1000000,[],dealWithResults);
}

TL;DR:不要运行长时间的计算,但如果必须,请让服务器为您完成工作并仅使用异步 AJAX 调用。服务器可以更快地完成工作,并且您的页面不会阻塞。

如何在客户端处理 JS 中的长计算的 JS 示例仅用于解释如果您没有执行 AJAX 调用的选项(99.99% 的情况下),您可能会如何处理此问题事实并非如此。

编辑

另请注意,您的赏金描述是 The XY problem 的经典案例

2019年编辑

在现代 JS 中,await/async 概念极大地改进了超时回调,因此请使用它们。任意await让浏览器知道它可以安全地运行计划的更新,因此您以“结构化就像同步”的方式编写代码,但将您的函数标记为 async ,然后你await每当您调用它们时,它们都会输出:

async doLongCalculation() {
let firstbit = await doFirstBit();
let secondbit = await doSecondBit(firstbit);
let result = await finishUp(secondbit);
return result;
}

async doFirstBit() {
//...
}

async doSecondBit...

...

关于javascript - 长时间运行函数的 DOM 刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46072489/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com