zoukankan      html  css  js  c++  java
  • innerHTML 延后执行?

    时常会觉得 innerHTML 可能有延后执行的情况,比如下面代码:

    document.body.innerHTML = 'something';
    alert('something else');

    明显发现,先是收到弹窗,再是 body 内容变了,所以会觉得 innerHTML 存在延后执行的情况,但是换个角度

    document.body.innerHTML = 'something';
    alert(document.body.innerHTML);//'something'

    这个例子直接否定了上面的猜测,证明,innerHTML 并不存在延后执行,延后执行的是页面的渲染,后来在 stackoverflow 上找到了答案,原理大概就是,

    代码执行的时候,是按照从上到下的顺序的,innerHTML 也并不存在延后执行,只是,因为 js 是单线程的,所以还在执行语句块的时候,按照顺序,修改了 DOM 元素的 innerHTML,然后继续执行后面的代码,等进程空闲,渲染页面,然后执行任务队列里的代码,也就是说,之前修改了 DOM 元素的 innerHTML,并不会立马重新渲染页面,因为这是两码事,js 本身是单线程,所以只能把代码执行完后,有空闲,再去渲染页面。

    那么如何去改善这种情况呢?想了几个方法:

    1、给后面的代码,加个定时器,把代码加到任务队列里;

    document.body.innerHTML = 'something';
    setTimeout(function() {
        alert(document.body.innerHTML);
    }, 0);

    因为 setTimeout 本身就是异步调用机制,高程解释:

    除了主JavaScript 执行进程外,还有一个需要在进程下一次空闲时执行的代码队列;

    定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行;

    如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行;

    考虑下面代码:

    setTimeout('alert(1)',0);
    alert(2);
    alert(3);

    此时的主线程和任务队列:

    队列里的代码等主线程空闲时才会执行,所以 alert(1),会等到alert(2),alert(3)执行完毕后再执行; 

    alert(1);
    alert(2);
    alert(3);
    

    此时的主线程和任务队列:

    所以代码按照从上往下的顺序正常执行; 

    回到这里 innerHTML 和 setTimout,

    document.body.innerHTML = 'something';
    setTimeout(function() {
        alert(document.body.innerHTML);
    }, 0);
    

    间隔 = 0 不影响异步的逻辑,本来是 innerHTML->alert()->渲染,现在就是 innerHTML->空闲?渲染->空闲?alert();

    setTimout(fn,0) 实际上是立即把 fn 添加到了任务队列里,既然是队列,代码执行就是从第一个开始到最后一个结束;

    实际上,猜测,页面渲染会在进程空闲时,立马执行,然后再去执行任务队列里的代码。所以等主线程空闲时,首先执行的是渲染,然后执行的 alert();

    不信?考虑下面代码:

    let header = document.getElementsByTagName('header')[0];
    setTimeout(() => { alert('s') }, 0)
    header.innerHTML = 'hello';
    i = 100000;
    while (i > 0) {
        i--;
    }
    alert('done');

    chrome 62,先弹出 done,然后页面修改了,弹出了 s;

    firefox ,有点怪异,done 和 hello 几乎同步,然后是 s;(逻辑上 alert 阻塞了进程,所以弹出 done 的时候,hello 应该无法被渲染到页面,可能有优化)

    如果 innerHTML 的渲染,仅仅是作为普通的代码放到了任务队列里,那么肯定是 alert('s') 先弹出来(因为 alert('s') 是最早被添加到任务队列的),所以这里可以证明 innerHTML 的渲染,实际上还要早于任务队列里的代码;

    提示:这种页面渲染的问题,自然不仅仅是 innerHTML,涉及页面的很多操作可能都会产生类似的情况,这个需要留意;

    参考文档:

    Is innerHTML asynchronous?

    When does InnerHTML execute immediately?

    How to detect when innerHTML is complete 

    JavaScript 运行机制详解:再谈Event Loop

  • 相关阅读:
    live555源码研究(三)------UsageEnvironment类
    live555源码研究(二)------TaskScheduler类
    live555源码研究(一)------live555MediaServer的启动过程和基本类图
    (转)视频监控相关文章
    【流媒體】live555—VS2008 下live555编译、使用及测试
    【转】PostgreSQL IP地址访问配置
    red5研究(一):下载,工程建立、oflaDemo安装、demo测试
    SVN服务器的搭建和使用
    【转】linux下cvs配置
    【转】js正则表达式语法
  • 原文地址:https://www.cnblogs.com/xianshenglu/p/8320956.html
Copyright © 2011-2022 走看看