Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端性能优化小结 #22

Open
liusaint opened this issue Mar 2, 2018 · 0 comments
Open

前端性能优化小结 #22

liusaint opened this issue Mar 2, 2018 · 0 comments

Comments

@liusaint
Copy link
Owner

liusaint commented Mar 2, 2018

  1. http优化,加大并发,减少请求数量以及传输量
  • domain hash技术突破并发限制。http1.x浏览器对于发起的连接有并发限制,这个限制是针对域名的,所以将静态资源放在多个不同的域名下,也可以突破这个限制。但是也不宜使用太多域名。会增加额外的dns解析成本。
  • 合理使用http头。使用expires,cache-control,Etags等http头缓存静态资源。这篇文章介绍的很详细:https://zhuanlan.zhihu.com/p/30780216
  • Connection:keep-alive。保持tcp连接。避免三次握手以及tcp的慢启动开销。
  • 合理利用空闲时间做一些预操作。预测用户的大概率行为,在页面空闲时加载后续所需要的资源。dns预解析。TCP预连接。页面预渲染。有一些标签属性已经可以很好的做到这些,如prefetch & preload & dns-prefetch。
  • 合并css,js文件。
  • 图片压缩以及页面需要多大的图片就请求多大的图片。比如页面只显示20*20的图片,就不要返回一个500*500的图片。
  • cdn加速。
  • gzip压缩。
  • 减少不必要的通信量,比如合并发送上报数据。
  • 按需加载模块资源。比如js,css。
  • 使用http2。
  1. 缓存请求,并保持缓存内容大小与性能之间的平衡。比如某个请求涉及大量的数据库操作,耗时很长,并且有一定概率多次请求。在这个数据的实时性和重要性不是那么强的情况下,我们可以将请求结果缓存到变量中或浏览器的一些别的存储机制中。但是缓存内容过多也会对性能有影响,所以我们也要根据一定的规则(比如访问频率,访问先后时间,缓存总数量等)及时地清除部分缓存。如果不想改动代码,那么http响应可以返回Expires http请求头,在过期之前就不再发请求。

  2. cookie优化,减少cookie传输量

  • 避免cookie太庞大。不要什么都往cookie上放。cookie的主要作用在于身份识别,而不是信息存储。因为每个请求都会带着cookie,无形中会加大很多传输量。前端的话可以使用一些其他的替代存储方式。比如localStorage,sessionStorage。
  • cookie free技术。将一些静态资源放在与主域不同域名的服务器上,浏览器请求的时候就不会带上主域的cookie了,从而减少传输量。
  1. Bigpipe技术。产生于Facebook公司的前端加载技术,它的提出主要是为了解决重数据页面的加载速度问题,是一种数据渐进式预加载方案,基于HTTP Chunk。

  2. PWA技术。service worker。

  3. 避免空的src和href。

  4. 图片懒加载。lazy load。

  5. 脚本加载优化

  • script标签放到页面最后,</body>标签前面,避免阻塞页面渲染。一个讨论:https://www.zhihu.com/question/20027966。
  • 合并,压缩脚本。减少连接数和数据传输大小。
  • 无阻塞的脚本
    • script标签添加defer,async属性。
    • 动态生成script标签。使用onload事件或onreadystatechange事件来检测脚本加载完从而执行加载完之后的回调。
    • 使用ajax方式加载js内容。插入一个script标签中。好处是加载完之后不会立即执行。
  1. JS数据存取
  • 减少作用域查询。作用域链的查询,变量的位置越深,查询速度越慢。而全局变量在作用域链最深。所以,对于使用一次以上的跨作用域变量我们应该把它用局部变量存起来。
  • 避免内存泄露。
    • 循环引用
    • IE,闭包中有dom对象。
  • 减少嵌套成员的查找。可缓存在局部变量中。类似var Dom = YAHOO.util.Dom;
  • 减少原型链查找。
  1. dom优化
  • 减少dom数量。如果页面dom数量太多,对性能是有影响的。
  • 减少dom访问与修改。dom与JavaScript相当于两个独立的部分以功能接口连接,会带来性能损耗。
  • 尽量不要在循环中更新页面内容。一个更有效率的版本将使用局部变量存储更新后的内容,在循环结束时一次性写入。
  • 不建议用数组的 length 属性做循环判断条件。访问集合的 length 比数组的length 还要慢,因为它意味着每次都要重新运行查询过程。
  • 使用快的API。比如document.querySelector()。
  • 事件绑定。
    • 多使用事件代理,而不是每个dom节点上去都绑定事件。
    • 考虑使用自已定义的事件管理器,一个dom上不要反复绑定事件。而是维护一个事件回调数组,像jQuery做的那样。
  • 减少回流与重绘。
    • 少使用.style一个属性一个属性地去改。而是合并到一起一起修改。比如用class来控制样式,或者cssText来批量修改。
    • 让要操作的元素进行"离线处理",处理完后一起更新。
    • 回流必将引起重绘,而重绘不一定会引起回流。
    • 减少对位置信息的属性读取以及getComputedStyle与currentStyle的使用。浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。如果代码中频繁读取实时位置属性,会导致浏览器多次重排。引起性能问题。
  1. 异步优化任务。分割任务异步执行,让出线程。
  • 如果用户的操作100ms得不到响应,用户就会感觉到与应用失去联系。如果我们的代码执行时间太长,用户其他的操作得不到响应。所以如果我们无法减少脚本执行时间,我们可能考虑主动地让出线程。分解任务,异步执行。
    比如分解成多个任务使用setTimeout或setInterval来异步执行。
  • 但是如果我们任务分得太细,比如每个循环体算成一个任务,每个任务结束就让出线程,效率就很低了,因为setTimeout 和 setInterval 本来就设计的慢吞吞的,即使延时时间为0,浏览器环境下每秒也最多执行几百次。而换成while循环,每秒能执行几百万次。 所以我们每个异步任务中应该多处理一些任务,比如我们让它执行50ms。在每个异步中检测一下执行时间,加入while循环,时间如果小于50ms就继续执行,超过50ms就让出线程。这样既保证了不阻塞线程,也让我们的任务能尽快地完成。
  • 使用Web Workers。
  1. ajax的优化。目前一些比较成熟的库的ajax都是在ajax完全接收完响应之后才执行成功的回调。这里其实有很大的优化空间。
  • 一般的ajax封装是在XMLHttpRequest的readyState==4(整个请求过程已经完毕)的时候进行成功回调处理。而其实在readyState==3的时候(响应体下载中,responseText中已经获取了部分数据.)已经可以对已经接收到的部分内容进行处理了。比如几十万条数据从后端传过来,要插入dom。如果我们等到所有数据接收完毕,再一次性插入dom,可能会有很大的性能问题。但是如果我们在后台将数据以一定的方式拼装,然后前端接收到一部分处理一部分,就有两方面的性能提升,一方面是提前处理了数据,让用户可以更早地看到数据效果,另一方面是分解了任务。
  • 合并请求。比如多个图片base64格式加分割符一起发送过来。前端再把结果分割,分发到多个img标签上去。
  • 数据传递格式。不一定非要是json格式。其实可以很灵活。自定义的格式一方面可以减少数据传输量,另一方面更方便前端边接收边处理。
  1. 循环与递归
  • 尾调用优化。会将从内存中清除前面的调用栈,将调用栈清零。一方面是内存释放,另一方面是避免了调用栈溢出引起的错误。
  • 减小循环次数。每个循环体中多执行几个循环内容。
  • 减少循环体开销。比如使用倒序循环。
  • 缓存计算结果。使用Memoization技术来避免重复计算。
  1. 函数的节流与防抖,限制函数主体执行频率。频繁执行某些函数会严重影响性能,比如一些常见的触发频率很高的浏览器事件,如果每次触发都去执行回调甚至操作dom,性能影响很大,并且我们肉眼对dom变化的实时性要求并没有那么高。所以需要限制主体内容的执行频率。工具库underscore中提供了对应的_.throttle和_.debounce方法。
  • window对象的resize、scroll事件
  • 拖拽时的mousemove事件
  • mousedown、keydown事件
  • 文字输入、自动完成的keyup事件
  1. requestAnimationFrame方法。

  2. 逻辑优化,减少耗时操作。很多功能并不是只有一种途径去实现。如果一种操作特别耗时。也许可以优化一些逻辑就减少这样的操作。

  3. 定时器的控制。
    应用中存在过多的定时器会影响性能。特别是单页应用中,如果我们定义了一些定时器而没有随着场景消失而清掉定时器,还可能会产生很多逻辑上的问题。

  4. 正则表达式优化。

  5. css gpu加速。

补充:

20.memoize。缓存函数结果。对于某些递归效果特别明显。

欢迎补充交流。github地址:#22

参考:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant