jQuery / Javascript - 如何在继续执行函数之前等待被操作的DOM更新

时间:2011-09-08 01:01:27

标签: javascript jquery dom high-load

我要做的是在执行CPU密集型脚本之前更新一个简单的div来说“Processing ...”(运行需要3-12秒,没有AJAX)然后更新div来说“完了!”完成后。

我所看到的是div永远不会更新“Processing ...”。如果我在该命令后立即设置断点,则div文本会更新,所以我知道语法是正确的。 IE9,FF6,Chrome13中的行为相同。

即使绕过jQuery并使用基本的原始Javascript,我也会看到同样的问题。

你认为这会有一个简单的答案。但是,由于jQuery .html()和.text()没有回调挂钩,因此不是一个选项。它也没有动画,因此没有.queue可以操纵。

你可以使用我在下面编写的示例代码来测试这个,它显示了具有5秒高CPU功能的jQuery和Javascript实现。代码很容易理解。当您单击按钮或链接时,您永远不会看到“正在处理...”

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script type="text/javascript">
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    do {start = new Date();} while (end-start > 0);
    document.getElementById('msg').innerHTML = 'Finished JS';   
}
$(function() {
    $('button').click(function(){
        $('div').text('Processing JQ...');  
        start = new Date();
        end = addSecs(start,5);
        do {start = new Date();} while (end-start > 0);
        $('div').text('Finished JQ');   
    });
});
</script>
</head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>

4 个答案:

答案 0 :(得分:18)

将其设置为处理,然后执行setTimeout以防止cpu密集型任务在div更新之后运行。

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script>
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    setTimeout(function(){
         start = new Date();
         end = addSecs(start,5);
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished Processing';   
    },10);
}
$(function() {
    $('button').click(doRun);
});    
</script>
    </head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>

您可以根据需要修改setTimeout延迟,对于较慢的机器/浏览器,可能需要更大。

编辑:

您还可以使用警报或确认对话框来更新页面时间。

document.getElementById('msg').innerHTML = 'Processing JS...';
if ( confirm( "This task may take several seconds. Do you wish to continue?" ) ) {
     // run code here
}

答案 1 :(得分:2)

您有一个运行5秒的循环,并在此期间冻结Web浏览器。由于Web浏览器被冻结,因此无法进行任何渲染。您应该使用setTimeout()而不是循环,但我假设循环只是需要一段时间的CPU密集型函数的替代品?在执行函数之前,您可以使用setTimeout为浏览器提供渲染的机会:

jQuery的:

$(function() {
    $('button').click(function(){
        (function(cont){
            $('div').text('Processing JQ...');  
            start = new Date();
            end = addSecs(start,5);
            setTimeout(cont, 1);
        })(function(){
            do {start = new Date();} while (end-start > 0);
            $('div').text('Finished JQ');   
        })
    });
});

Vanilla JS:

document.getElementsByTagName('a')[0].onclick = function(){
    doRun(function(){
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished JS';   
    });
    return false;
};

function doRun(cont){
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    setTimeout(cont, 1);
}

您还应该记住始终使用var关键字声明所有变量,并避免将它们暴露给全局范围。这是一个JSFiddle:

http://jsfiddle.net/Paulpro/ypQ6m/

答案 2 :(得分:0)

我必须等待jQuery操作DOM ,然后进行更改(将表单字段多次加载到表单中,然后提交)。 DOM不断增长,插入时间越来越长。我使用ajax保存了更改,以使用户能够继续他离开的地方。

这确实无效

jQuery('.parentEl').prepend('<p>newContent</p>');
doSave(); // wrapping it into timeout was to short as well sometimes

由于诸如.prepend()之类的jQuery函数仅在完成后才继续执行链,因此以下内容似乎可以达到目的

jQuery('.parentEl').prepend('<p>newContent</p>').queue(function() {
  doSave();
});

答案 3 :(得分:0)

截至2019年,人们使用 double onChange() { //Do something } 跳过了一帧,而不是使用setTimeout创建竞争条件。

requesAnimationFrame