《DOM操作跨线程》

286 阅读3分钟

一.跨线程

浏览器的两个功能模块:渲染引擎,JS引擎,这两个线程各司其职

JS引擎只能操作JS,不能操作页面;渲染引擎只能操作页面,不能操作JS。

那么,当在JS里写 document.body.appendChild(div1)时,JS是怎么把div1放到页面中的?是通过跨线程通信做到的。 浏览器发现JS在body里加了一个div对象,浏览器就通知渲染引擎,往页面的body里也新增一个div元素,他的所有属性照抄div对象。

图示跨线程通信:

在JS中:

  1. 在div放入页面之前:

    let div=document.createElement('div')
    div.innerText='hi'
    

创建div,向div插入文本,都属于JS线程内的操作,与DOM无关。

  1. 在div放入页面之时:
    document.body.appendChild(div)
    

浏览器发现JS要改变页面的内容,就通知渲染引擎在页面中渲染一个div元素。这步是跨线程的。

  1. 把div放入页面之后:

之后再对div进行的操作都有可能会触发重新渲染。

  • 改id可能会重新渲染,如果这个id有颜色之类的样式
    div.id='newid'
    
  • 甚至改title也有可能会重新渲染

这时如果修改title属性,页面也会重新渲染。

  • 如果浏览器发现你连续对div进行了多次操作,浏览器可能会给合并成一次操作,也有可能不会:

想实现一个动画,宽度由100变到200.但是没有出现动画,为什么?

因为浏览器发现在短时间内对div的classList进行了两次操作,浏览器就把两次合并成一次渲染了,那怎么不让他合并呢?

可以在JS的两次操作中间加一句

test.clientWidth

获取这个div的客户端宽度,就会出现动画了。获取宽度不会改变其他东西,但是会让浏览器先渲染第一步,先加一个start类,然后再获取宽度,再加end类,这样就不会合并了。

二.属性同步

在JS里改变页面中div元素的innerText,那么页面对应的文本也会修改。是不是在JS里改div的所有属性都会在页面中对应的更改呢?

在页面中的div元素有三个属性,id ,x ,data-x的值都是'test',在JS中都把他们改成'hu',执行JS之后,发现id和data-x的改变被同步到页面中了,x属性的更改没有同步,还是原来的值。

  • 标准属性

对元素的标准属性的修改,会被浏览器同步到渲染页面中。比如 id,className,title等。

  • data-*属性

同上,会被同步修改。

  • 非标准属性

对非标准属性的修改,如自定义的x属性,只会停留在JS线程内,不会同步到页面里。

如果你有自定义属性,想被同步到页面中,请使用data-作为前缀。

三. Property V.S. Attribute

  • property:属性,表示JS线程内div这个对象的所有属性。 id,className,style
  • attribute:也是属性,表示渲染引擎内div对应的标签的属性。id,class

如果是同名的标准属性,他们的值会相等。但是如果不是标准属性,可能不会同步更改。