最近毕设碰到的一个问题
我向dom中添加一个节点,然后使滚动条滚动到底部
很简单的一个需求,但是做的时候发现,window.scrollTo(0,dom.scrollHeight)
并没有像想象中一样使滚动条底部,而节点的确已经添加进去了。
原因:浏览器加载机制js在css之前,当添加节点的js执行之后,节点并没有立即添加到页面,因为还有同步的js代码没有执行,js线程阻塞了GUI渲染线程,所以当执行window.scrollTo
的时候,并没有跳到页面底部。
解决方法:将调到底部的window.scrollTo(0,dom.scrollHeight)
设为异步执行,异步执行的函数不会阻塞线程,而是等待所有同步代码执行完毕后,才开始异步队列函数的执行,因此通过setTimeout(fn,0)
,当vue中diff算法(需要时间,并且在跳转之前并未完成,vue使用的就是nexttick,在settimeout之前执行)操作,浏览器渲染完毕后,主线程空出才会执行该跳转代码。
Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列,所以数据变更后想要立即操作dom,需要把操作写在同一个队列的异步操作中,或者写在下一个Vue.nextTick()中。
在node中还存在
process.nextTick
/setImmediate
控制代码在事件队列中的执行,执行顺序为
执行队列--->process.nextTick(fn)--->setTimeout ~= setlmmediate
。