时常会觉得 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

innerHTML 延后执行?的更多相关文章

  1. golang defer 延后执行什么

    对于golang的defer,我们已经知道,defer定义的语句可以延后到函数返回时执行. 经常用在文件的关闭,锁的释放等场景中.而且defer定义的语句即使遇到panic也会执行.这样,可以执行必要 ...

  2. linux 延后执行

    设备驱动常常需要延后一段时间执行一个特定片段的代码, 常常允许硬件完成某个任务. 在这一节我们涉及许多不同的技术来获得延后. 每种情况的环境决定了使用哪种技术最好; 我们全都仔细检查它们, 并且指出每 ...

  3. 延宕执行,妙用无穷,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中defer关键字延迟调用机制使用EP17

    先行定义,延后执行.不得不佩服Go lang设计者天才的设计,事实上,defer关键字就相当于Python中的try{ ...}except{ ...}finally{...}结构设计中的finall ...

  4. ready是先执行的,load后执行,DOM文档的加载步骤

    在jq中在文档载入完毕后有这几种方式去执行指定函数: $(document).ready(function() { // ...代码... }); //document ready 简写 $(func ...

  5. 泛函编程(11)-延后计算-lazy evaluation

    延后计算(lazy evaluation)是指将一个表达式的值计算向后拖延直到这个表达式真正被使用的时候.在讨论lazy-evaluation之前,先对泛函编程中比较特别的一个语言属性”计算时机“(s ...

  6. 读书笔记_Effective_C++_条款二十六:尽可能延后变量定义式的出现时间

    这个条款从字面意思还是很好理解的,就是在使用这个变量前才去定义,而不是很早就定义了它,而在很后面的时候才去使用.这个条款只适用于对变量声明位置没有要求的语言,比如C++.对于像C或者一些脚本语言,语法 ...

  7. iOS UITableView reloadData 刷新结束后执行后续操作

    如果在reloadData后需要立即获取tableview的cell.高度,或者需要滚动tableview. 如果直接在reloadData后执行代码是有可能出问题的,比如indexPath为nil等 ...

  8. databinding 填坑 绑定动作是延后生效

    binding = FragmentNewsMainLayout750Binding.inflate(inflater); homePageViewModel = new HomePageViewMo ...

  9. spring boot 配置启动后执行sql, 中文乱码

    spring.datasource.schema指定启动后执行的sql文件位置. 我发现中文乱码,原因是没有指定执行sql script encoding: spring: datasource: u ...

随机推荐

  1. vue组件调用(全局调用和局部调用)

    当用vue-cli创建一个项目后, 创建项目的方法: https://www.cnblogs.com/fps2tao/p/9376847.html 编写了组件怎么,在其他组件中调用了? 组件listB ...

  2. java Arrays对数组操作

    Arrays.sort(Array)对数组排序 public static void main(String[] args) throws IOException { int[] a = {1,3,9 ...

  3. 修改JQM的默认配置属性

    从本文开始,使用 jQuery Mobile 与 HTML5 开发 Web App 系列将会进入第三部分——jQuery Mobile 事件与方法,这其中将会利用之前所讲述的 jQuery Mobil ...

  4. Swift 3.1 的一些新特性

    Swift 3.1 的一些新特性   推荐序 本文来自泊学的投稿,介绍了 Swift 3.1 的新特性,感谢泊学授权发表.以下为文章正文. 正文 Apple 终于发布了Xcode 8.3以及Swift ...

  5. UASCO Wormholes 解析 and C 语言实现

    题目大意: 农场有N个洞(2<=N<=12,N为偶数),且组成N/2个连接对.每一个洞的给出平面坐标(x,y). 假设A和B相连,则进入A会从B出来,进入B会从A出来.有仅仅会沿着x轴正方 ...

  6. CSS3 实现厉害的文字和输入框组合效果

    最近在忙着弄网站,学到了不少效果,这又是一个厉害的  <html> <head> <meta http-equiv="Content-Type" co ...

  7. 关于Cocos2d-x开发一个游戏的过程自述

    我在2016年12月6号完成了我的第一个自己独立完成的游戏,期间遇到各种各样的问题和困难,但是幸运的是问题都一一被解决了,现在我想总结一个整个的制作游戏的过程 使用的环境是VS2013+cocos2d ...

  8. 什么是Spring Cloud

    Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载均衡.断路器.数据监控等,都可以用 ...

  9. Android开发人员必备的10个开发工具

    工欲善其事,必先利其器,Android SDK 本身包含很多帮助开发人员设计.开发.测试和发布 Android 应用的工具,在本文中,我们将讨论 10 个最常用的工具. 1.Eclipse ADT E ...

  10. 百家搜索:在站点中加入Google、百度等搜索引擎

    来源:http://www.ido321.com/1143.html 看到一些站点上加入了各种搜索引擎. 如Google.百度.360.有道等.就有点好奇.这个怎么实现?研究了一各个搜索引擎怎么传送k ...