海阔凭鱼跃,天高任鸟飞。Hey 你好!我是秦爱德。????
导读
就在前不久,共事写了一个拖拽右边 菜单栏 扭转 菜单栏宽度 从而失去更好的交互体验成果。But! 美中不足的是拖拽的时候如果手速过快,会导致卡顿成果,看起来非常好受。通过一直调试,最终是应用了 setTimeout 解决了该问题。那么问题来了!为什么 setTimeout 能解决动画卡顿问题呢?
一图胜千文,通过两张图的前后比照,咱们来看看实际效果!
(这是没有加上 setTimeout 之前,有显著卡顿????????????)
(这是加上 setTimeout 之后,拖拽成果显著顺畅了不少????????????)
假如发问:会不会是内容过多导致的呢?????
为了证实我这个猜测,故将内容切换到比拟少模块。
果然,拖拽成果霎时晦涩了许多????????????
这个时候根本能够确认是内容过多导致的卡顿,那如何保障不扭转内容大小的状况下达到拖拽顺滑的成果呢?
提出解决方案:是否通过缩小回流次数来节俭性能,从而使得拖拽顺滑呢?????
为此,故将左边内容固定宽度,拖拽菜单的时候,因为左边内容盒子宽度曾经固定,所以不会造成元素盒子尺寸发生变化,故不会触发 回流。
果然,拖拽成果再次晦涩了许多????????????
什么是回流与重绘?
回流: 当咱们对 DOM 的批改引发了 DOM 几何尺寸的变动(比方批改元素的宽、高或暗藏元素等)时,浏览器须要从新计算元素的几何属性(其余元素的几何属性和地位也会因而受到影响),而后再将计算的后果绘制进去。这个过程就是回流(也叫重排)。
重绘: 当咱们对 DOM 的批改导致了款式的变动、却并未影响其几何属性(比方批改了色彩或背景色)时,浏览器不需从新计算元素的几何属性、间接为该元素绘制新的款式。这个过程叫做重绘。
由此可知:重绘不肯定导致回流,回流肯定会导致重绘!
通过管制内容宽度,缩小回流操作的确解决了卡顿问题,但该操作导致页面无奈自适应了,无奈适配各种尺寸的屏幕。那么还有什么方法是能够既不扭转内容大小,也不扭转内容盒子尺寸从而解决菜单拖拽卡顿问题呢?
是否通过打乱模块申明周期,扭转工作执行程序来使得拖拽顺滑呢?????
如题目所示,当咱们将扭转元素尺寸的代码搁置到 setTimeout 中。利用 setTimeout 实现一种 伪多线程 的成果,从而解决了拖拽卡顿问题!
对于这一点,波及到的背地常识还是挺多,莫慌!请接着往下看????????????
浏览器渲染过程(简述)
当咱们在浏览器输出网址到页面出现,在浏览器渲染这一层面,大体上须要经验三个步骤(下载 ???? 解析 ???? 布局):
1:依据页面 URL 向服务器发送一个申请,服务器响应页面的 HTML。浏览器首先去下载 html,js,css,图片,字体等一系列资源。
2:浏览器将 html 解析成为 dom tree(节点树),将 css 解析成为 rule tree(规定树),二者联合成为 render tree(渲染树)
3:渲染树构建结束之后,浏览器的渲染引擎将遍历渲染树把每个节点绘制进去,从而呈现出咱们所看到的页面成果。
浏览器刷新的频率大略是 60 次 / 秒,也就是说刷新一次大略工夫为 16ms。如果浏览器对每一帧的渲染工作超过了这个工夫,页面的渲染就会呈现卡顿的景象。
浏览器过程与线程(简述)
咱们都晓得 JavaScript 是单线程的,然而浏览器是反对多过程啊。所以,配合浏览器的正当调配,各个过程各司其职,玩儿的不可开交。
什么是过程?
过程是 CPU 进行资源分配的根本单位
什么是线程?
线程是 CPU 调度的最小单位,是建设在过程的根底上运行的单位,共享过程的内存空间。
浏览器蕴含了那些过程?
1:浏览器过程(负责浏览器级别的操作,如:标签页的创立和销毁、资源的治理与下载等)
2:第三方插件过程(负责第三方插件的应用)
3:GPU 过程(负责 3D 绘制和硬件加速)
4:浏览器渲染过程(浏览器内核负责 HTML,CSS,JS 等文件的解析和执行)
浏览器渲染过程(浏览器内核详解)
浏览器渲染过程次要蕴含了 5 个线程:
1:GUI 渲染线程
2:JS 引擎线程
3:计时器线程
4:定时器触发线程
5:异步 Http 申请线程
GUI 渲染线程与 JS 引擎线程是互相排挤的,因为二者不可能同时进行。试想一下,渲染线程这边正在渲染一个 div 的背景色,JS 引擎线程那边可劲儿的通过 js 扭转你这个 div 元素的背景色以及尺寸啥的。那么这时候到底以那一边为规范。非得乱套不可。所以,当执行其中任何一个线程的时候,另一个线程操作则被挂起,期待其余工作执行结束之后,再回来执行这边的工作。
理解了这些前置常识后,咱们还须要理解一下宏工作微工作,以及事件循环、工作队列等常识。这里我不做过多讲述,可浏览
Jiasm 写的十分好的文章!传送门 - 走你????????????
对于 setTimeout
setTimeout 函数用来指定某个函数或某段代码,在多少毫秒之后执行。
setTimeout 会将指定的代码移出本次执行,等到下一轮 Event Loop 时,再查看是否到了指定工夫。如果到了,就执行对应的代码;如果不到,就等到再下一轮 Event Loop 时从新判断。这就阐明 setTimeout 指定的代码,必须等到本次执行的所有代码都执行完,才会执行。
setTimeout 扫盲:
1: setTimeout 中的 this 关键字将指向全局环境,而不是定义时所在的那个对象。
2: setTimeout 是一个异步工作,并且是一个宏工作。所以是最初执行的工作。
3: setTimeout 执行回调间隔时间长度
setTimeout(() =>{console.log('hello');
}, 100)
留神:这里的工夫距离长度肯定是大于 100ms 的,具体大于多少取决于在此之前同步工作执行的 js 须要占用多少工夫。
4: setTimeout(func,0)与 setTimeout(func)的区别
setTimeout(func,0):示意让 func 回调函数挂起,等到所有同步工作以及工作队列外面的工作执行结束之后,立马执行 func 函数。事实上,0 毫秒实际上达不到的。setTimeout 推延执行的工夫,起码是 4 毫秒。
setTimeout(func):如果没有传递具体延迟时间,浏览器将为定时器主动调配工夫,具体调配多少因浏览器而异。
5: setTimeout 的延迟时间最大值是多少呢?
答案是:2147483647 毫秒(24.8 天),超出这个工夫,将作为溢出解决,即等同于 setTimeout(f,0)的成果。
6: setTimeout 将返回一个示意计数器编号的整数值,将该整数传入 clearTimeout 就能够勾销对应的定时器。
————– 富丽的分割线 ————–
秦爱德你说了这么多,这跟拖拽卡顿有啥关系啊?????????????
哈哈,你别慌,咱们一步一步来,接下来我就给你介绍一波 setTimeout 的理论用处!????????????
用处以一:调整事件的产生程序
setTimeout(() =>{console.log(2);
},0)
console.log(1);
咱们都晓得 js 在解析代码的时候是逐行执行的,只有当遇到异步工作的时候,才会将异步工作挂起放到同步工作之后执行。所以咱们正好利用这个个性,来打乱事件执行程序,以满足特定的需要场景。
用处二:宰割耗时工作
咱们都晓得 javascript 是单线程的,其特点就是容易呈现阻塞。如果某一段程序处理工夫很长,很容易导致整个页面卡住。干不了其余事儿,这时候便能够应用 setTimeout 来将这些工作宰割从而解决此类问题。
用咱们拖拽扭转元素宽度举个栗子????
... 其它代码
document.onmousemove = function (e) {
... 其它代码
setTimeout(() =>{document.getElementById("app").style.width = xxx + 'px'
},0)
}
如上代码,咱们在拖拽元素的过程中,频繁的触发 回流 操作,而回流操作自身就是十分 低廉 的。这个时候就很容易呈现 阻塞 ,导致网页卡顿。这时咱们加上 setTimeout,奇妙的将这部分操作进行一个宰割解决,将工作放到浏览器最早可得的闲暇时段执行,那些计算量大、耗时长的工作,别离放到 setTimeout(f,0) 外面执行(分片塞入队列),这样即便在简单程序没有解决完时,咱们操作页面,也是能失去即时响应的。
用处三:事件防抖与节流
对于这一部分的内容,如要细说又是简明扼要了,这里间接举荐浏览
小不点别打我 写的十分不错的文章 [
传送门 - 走你????????????](https://juejin.im/post/687214…
好啦!对于一个拖拽卡顿问题引发出对 setTimeOut 的摸索就简略的介绍到这里了,由此可见,一个小小的问题,背地也须要弱小的理论知识撑持。所以,把握好 js 的一些底层原理常识,才是咱们晋升集体能力,进入下一个阶段的关键步骤。这里安利一句我特地喜爱的名句:
80% 的问题能够用 20% 的常识解决,而剩下的那 20% 的问题则须要你用 80% 的常识积攒去解决了。
感激
点赞???? 再看,已成习惯!该系列继续更新,你们的一键三连就是我继续写作的最大能源,如果对本篇博客有任何意见和倡议,欢送小伙伴们留言!欢送来扰!????????
本文首发于公众号「前端秦爱德」,欢送关注。
感兴趣的小伙伴还能够退出我的「秦爱德前端交换群」,我在成都下班儿,群里有少量成都外乡优良大佬以及美女 HR,如果你碰巧也是成都的,那就赶快进来吧。
我是秦爱德,一个在互联网夹缝求生的程序员!欢送关注我的集体公众号“前端秦爱德”