时常会觉得 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. unity, standard shader消耗两个draw call

    假设场景中只放一个球,关掉阴影和skybox,球体使用Unlit/Texture shader,则draw call数为2(背景占一个draw call,球占一个draw call). 相同情况下若将 ...

  2. python登陆Tom邮箱的代码一例

    本文出处参考:http://www.cnblogs.com/LinuxHunter/archive/2010/11/30/1891635.html 在很多的python 教程中都会讲到登录邮箱或发送邮 ...

  3. Atitit.数据库新特性战略规划 mssql sql server 2008 SQL2012 SQL2014

    Atitit.数据库新特性 mssql sql server 2008 SQL2012 SQL2014 1. Sql2012 新特性 1 1.1. 增加了Sequence对象. 1 1.2. 新的分页 ...

  4. Atitit.c# .net 3.5 4.0 4.5 5.0 6.0各个版本新特性战略规划总结

    Atitit.c# .net 3.5 4.0 各个版本新特性战略规划总结 1. --------------.Net Framework版本同CLR版本的关系1 2. paip.----------- ...

  5. iOS之美: UIView 与 UIWindow之间的关系

    转自:http://leopard168.blog.163.com/blog/static/168471844201381584533466/ 面对iOS初学者,总会被问到一些不常被关注的问题,比如: ...

  6. makefile之strip函数

    #$(strip <string> ) #名称:去空格函数--strip. #功能:去掉<string>字串中开头和结尾的空字符,并将中间的多个连续空字符(如果有的话)合并为一 ...

  7. css 盒子垂直居中

    面试的时候经常会被问到这样一个题目:让一个元素中内容垂直居中怎么做.其实之前,我就会两种,line-height和table-cell,今天做项目,遇到了这个问题,就系统的查了一下,总结一下方法: 1 ...

  8. request的生存期只限于服务器跳转

    症状: 刚才想做一个实验,在a.jsp中向request添加属性(页面编码为UTF-8),在b.jsp中删除该属性(页面编码为ISO-8859-1),通过ServletRequestAttribute ...

  9. jquery $.each 和for 怎么跳出循环(终止本次循环)

    1.for循环中我们使用continue:终止本次循环计入下一个循环,使用break终止整个循环. 2.而在jquery中 $.each则对应的使用return true  和return false ...

  10. java ssm框架入门(三)正式项目的web.xml配置

    一个正规的上线的web.xml的配置. <?xml version="1.0" encoding="UTF-8"?> <web-app id= ...