事件里面元素怎么立即刷新dom(页面),而不是等所有代码运行完再刷新。(强制刷新DOM)

事件里面元素怎么立即刷新dom(页面),而不是等所有代码运行完再刷新。

用js更新dom是web系统中经常出现的场景,但是有时候可能会遇到这样的情况,在更新dom之后还执行了一段运行时间可能比较长的js代码,这时你会发现,你更新的dom不会立刻在页面显现出来,而要等所有js都执行完之后才能出现。

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="gbk" />  
        <title>Test Refresh</title>  
        <script src="js/jquery-1.7.1.js"></script>  
        <script type="text/javascript">  
                  
                function runLongOperation(){  
                    var d = new Date().getTime();  
                        while (1) {  
                            var current = new Date().getTime();  
                            if (current - d > 3000) {  
                                console.log("good");  
                                break;  
                            }  
                        }  
                }  
                  
                $(function(){  
                    $("#submit1").click(function(){  
                        var $n = $("#name");  
                        $n.hide();  
                        runLongOperation();  
                    });  
                });  
        </script>  
    </head>  
    <body>  
            <input type="text" placeholder="please input your name" name="wd" id="name"/>  
            <input type="button" name="submit1" id="submit1" value="Hide"/>  
    </body>  
</html>  

点击按钮后首先执行的操作是隐藏输入框name,然后执行了一段长约3秒钟的操作,你会发现点击按钮后隐藏输入框的动作并不会立刻在浏览器上体现,而是等到runLongOperation执行完之后才发生(我试了在chrome,FF和IE上均是如此)。为什么会这样呢,在stackoverflow上找到一个大神的解释,“Mozilla (maybe IE as well) will cache/delay executing changes to the DOM which affect display, so that it can calculate all the changes at once instead of repeatedly after each and every statement.”。也就是说,浏览器会cache住影响dom展现的操作,直到所有的js都执行完,这时候它可以一次性地更新需要更新的dom,这样做可能是出于性能的考虑。

通常来说,这不会有什么问题,但有的时候也许会带来一些体验上的不同。以我最近接触的一个系统的场景来说,点击一个tab页签会加载一个页面,加载完后会执行先关的初始化js,也就是在set完这个tab容器的content后还要执行一段js。不幸的是,这段js执行的时间有点长(由于历史原因这段js必须执行),大约1~2秒的时间(IE下),所以用户会在点击tab页签后并不能马上看到页面,而是看到一个空白的区域并等待一段时间才能看到正常的画面,这就给了用户不好的体验。为了消除这个影响,我们想要强制浏览器让内容先展示出来,再执行剩下的js,使用户可较快地看到结果,虽然接下来js的执行的js也会影响用户的操作(单线程),但因为用户在点开页面后通常有段时间是不做任何操作的(通常要先看一眼什么的),这段时间可以让坑爹的js执行完。

接下来的问题是如何让浏览器强制刷新更新后的dom呢,我们找到了几种方法:

1.更新dom的js执行完后执行alert,会强制浏览器刷新dom。这个方法简单有效,但无可操作性,不可能在系统中无缘无故弹出一个alert框。

2.根据stackoverflow上某位大神的说法,“To force an update (to force an immediate, synchronous reflow or relayout), your JavaScript should read a property that’s affected by the change, e.g. the location of someSpan and otherSpan.:”,即是如果让js去读被改变的dom节点的相关属性,则可以迫使浏览器更新dom。但遵照这个思想试验只好发现没有起效,不知是否我的操作方法不当??望有高人指点!!

3.借助setTimeout,把后面影响刷新的js放在setTimeout里面执行。按我的理解,原来的一大段js是处在一个同步执行的逻辑中的,而浏览器会延迟一个dom刷新的机制也只是作用在同步代码中,如果我们将后面的js放在setTimeout里面,那相当于后面的代码处在一个异步逻辑中,浏览器就会认为当前的同步逻辑已经完成,可以刷新更改的dom了。但是,setTimeout的时间也不能设得太小,如果设为0,你会发现仍然可能不能立刻刷新更改后的dom。我想也许这跟各个浏览器的任务调度有关,当前的同步逻辑执行完之后,浏览器刷新dom的操作可能会被另一个任务抢占了,经试验把timeout的时间设在100左右较为理想。。。顺带提一句的是,js引擎都是单线程处理任务队列的,任何异步编程都是障眼法,可参考http://www.cnblogs.com/jeffwongishandsome/archive/2011/06/13/2080145.html。

最后,我的解决方案是将之前的代码改成如下形式:

$(function(){  
$("#submit1").click(function(){  
   var $n = $("#name");  
   $n.hide();  
   setTimeout(runLongOperation, 100);  
})  
})  
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值