前端性能优化(三)——传统 JavaScript 优化的误区

javascript
用户体验
前端性能优化
技术分享
browserinsight

#1

注:本文是纯技术探讨文,无图无笑点,希望您喜欢
##一.前言
软件行业极其缺乏前端人才这是圈内的共识了,某种程度上讲,同等水平前端的工资都要比后端高上不少,而圈内的另一项共识则是——网页是公司的脸面!

几年前,谷歌的一项统计表明,如果亚马逊页面加载每慢100ms,将影响他们1%的收入;如果谷歌页面加载慢500ms,流量将锐减20%,这个数据现在必将更加恐怖!

前端高性能优化(一)(二)中,笔者介绍了一些关于前端优化的技术,这些技术都依赖于前人的辛苦努力,但我们仍要明白的是,前端的情况十分复杂,优化前端性能是必须因地制宜、因时制宜。

在本篇文章中,主要介绍的就是在一些条件下,传统优化JavaScript的技术并不像我们认为的那样适用。
##二.JavaScript 模块化误区
加快 JavaScript 加载和执行的速度,一直是前端优化的一个热点。因此我们先来说下 JavaScript 模块化技术的相关知识,希望通过实践来体现模块化技术在使用时的注意事项,避免滥用。

为什么会有模块化技术?

长久以来,编写 JavaScript 一直以文件为单位,一般一个类型的 JavaScript 功能代码会被放在同一个文件里。在一个页面里,引用的文件一般是写死的,也就是不管页面用不用,只要你引入了这个文件,这个文件就会被加载。

举个例子,我们开发了一个内容复杂、功能强大的页面,JavaScript 文件大到 500K,当页面费劲的把这 500K 加载下来,然而用户真正只使用了这 500K 里极少的一部分功能,但我们又不得不把这 500K 加载下来,因为不同的用户使用的功能点可能不一样,我们必须满足所有需求。

而模块化技术提出 按需加载,也就是当用户触发该功能的时候,那个功能才真正的被加载。好比 500K 被拆成了 50 个模块,每个模块 10K,当用户触发一个功能时,加载 10K,再触发再加载,以这样懒加载的方式来加载模块,可以很大的提高响应速度。这样,管理模块懒加载的技术也随之诞生。

模块化技术并非到处靠谱!!

之前笔者在网上搜索到了一个模块化技术:SeaJS。它是一个遵循 CommonJS 规范的 JavaScript 模块加载框架,可以实现 JavaScript 的模块化开发及加载机制。与 JQuery 等 JavaScript 框架不同,SeaJS 不会扩展封装语言特性,而只是实现 JavaScript 的模块化及按模块加载。

SeaJS 的主要目的是令 JavaScript 开发模块化并可以轻松愉悦进行加载,将前端工程师从繁重的 JavaScript 文件及对象依赖处理中解放出来,可以专注于代码本身的逻辑。说白了就是有 Lazy Load 的特性,用到某模块时,SeaJS 才会去加载模块的 JS 文件。我们可以按功能划分多个模块,触发模块功能时,SeaJS 先加载功能模块的文件,然后执行相应的功能。

这个 SeaJS 拥有的特性,初看非常吸引人,它可以说是新定义了一种开发和管理 JavaScript 文件的模式。遵循这个模式,你会享受起 JavaScript 的开发。

实践证明,它也的确可以使 JavaScript 模块化,根据功能划分模块,每个模块对应一个 JavaScript 文件,当执行到模块的功能,或者你需要加载模块时,模块才会被下载,同时不会造成重复下载。这一切看起来如此的合理,如此的顺畅。。。。。

但是我在使用后发现了一些 问题:由于网站功能相对简单,JavaScript 文件并不是非常大,过多的模块,反而会导致总加载的时间变多了。

由于是 Lazy Load 特性,不适合的模块划分导致网站出现反应慢的现象,原因是得先加载模块的文件,才能执行模块的功能。当网络情况不好时,该现象表现的更为严重!!!

可以说,问题出在了对新技术的不了解上,从而出现了问题,预期是 SeaJS 可以处理 JavaScript 优化的问题,因为它具有避免加载不必要模块的功能,结果反而南辕北辙。

总结

虽然尝试出现了问题,但是,收获也是巨大的,简单来说就是以下两点:

1)因地制宜,根据实际需要使用模块化技术,切勿跟风技术,在自己没有完全掌握时,谨慎用于产品中。

2)模块如果是懒加载的,粒度不能太小,也就是模块不能太小。

根据 大功能来划分模块 也是一个不错的尝试。

笔者尝试将所有模块划分为 基础模块功能模块 ,基础模块包括页面头部,尾部相关的公共部分,功能模块则根据前后台划分,前台部分,又根据具体的页面来划分,能合并到一起的,就合并成一个模块,增加粒度。结果 JavaScript 文件减少,也达到了预期的效果。

从实际体验来看,对于小型网站来说,没有必要使用懒加载 JavaScript 的相关技术,因为本身 JavaScript 文件就不是非常大。因此在网页加载时,就可以先加载所需要的模块。避免不必要的延迟。

##三.JavaScript 的位置问题

这一部分,我们来说说 JavaScript 的位置问题对网页网站性能的影响。

为什么要考虑位置问题?

其实不管是 CSS 还是 JavaScript,都需要考虑位置的问题,因为 HTML 的渲染和加载顺序是从上往下,也就是如果前面插入了 JavaScript 的引用,那么必须等到这个 JavaScript 下载完毕才会渲染后续的部分。

因此 JavaScript 的插入位置就成为一个值得考虑的问题,因为不适合的位置可能引起渲染的延迟等,造成不好的用户体验。

传统方案带来的问题和思考

CSS 放在头部,JavaScript 放在尾部,这是传统的经验,它的好处是可以让页面优先渲染, 从而页面可以快速显示。

但有事实往往没有我们预想的那么美好。

有的时候会出现这么一种情况:当页面已经渲染完毕时,我们立刻去使用网站的功能,但很多时候 功能按钮会没有反应。原因也很简单,就是 JavaScript 放在页面的尾部,还没来得及加载。。。。

这就纠结了。。。。

两种 JavaScript 放置方式,一种放在头部,一种放在尾部(暂时忽略部分放在头部,部分放在尾部的方式),一个牺牲了渲染速度,一个牺牲了用户体验。所以很多时候js的问题我们需要做权衡。

对一般的小型网站来说,用户体验问题要远远大于页面渲染的问题,就比如上文提到的那种功能按钮不可用的情况。而且,如果JavaScript不是很大的话,放在头部就很好,既不会有太久的页面空白,也能让其优先加载,二者得到了很好的平衡。

因此,很多经验上的东西并不是绝对的,一定要根据实际的情况,包括功能特点、服务器网络情况等来综合考虑。

为此,笔者写下一个自认为较为合理的位置选择方案,仅供参考。

图 1. 判断 JavaScript 放置位置决策表

从上面的分类介绍,我们也可以看出,将功能代码按类型归类到不同的 JavaScript 文件是多么的重要,比如应该放头部和应该放尾部的代码,最好不要合并在一起,不要等到出问题要优化的时候再去整理和重构,这样会增加很多不必要的工作量。

这不仅仅是为自己工作负责,也是为后面要读你代码的新人负责。养成好的设计编码习惯,也是技术积累的一部分。最后再根据 JavaScript 文件的功能类型,来决定是放在页面的头部还是尾部。

##四.怎样确定是不是 JavaScript 的问题?
这个问题在之前的前端高性能优化(一)(二)中也都简单的说过,之所以在这再次提及是因为确实觉得这个工具用着很舒服。

没错,就是舒服。

随着信息爆炸时代的到来,网站本身性能也深刻影响着公司的形象、利益等问题。但是大多数前端测试工具都太碎片化,没有办法针对多个使用场景,而且很多都是想 yslow 这样简单打个分,也不是真实的用户体验。前一段时间在网上找到了一款前端性能优化分析工具——Browser Insight,里面的功能相当全面,而且可以针对多个使用场景,包括:PC端,移动微信,移动浏览器,移动webview,还是 真实的用户体验,也就是说,用户访问你的网页是什么样的,从这个工具中体现出的就是什么样子的。

基于 JavaScript 这个维度 Bi 做的也是相当丰富了。

首先是 脚本错误 板块。Bi 里面可以从不同的时间维度查看被监控页面出现过的脚本错误,具体信息包括:发生时间、设备类型、报错的浏览器及其版本号、具体到堆栈信息都可以看到,不论是 线上还是线下测试或者页面维护 都是够用了。

不但能看到时间、系统、浏览器等,还可以具体定位到出错的代码行,这个确实很方便。

图一.Bi 脚本错误

其次是页面响应时间板块,这个算是意外的收获了。通过响应时间板块里面的慢加载追踪,可以看到本次慢加载的页面资源加载情况,然后我们就知道该优化哪个页面的哪些 js 、css、img等。

图二.Bi 资源列表-时序图


##五.前端优化?用户体验?
各位看客,如果你真能坚持看到这里,是否会觉得这篇更像解决用户体验问题的文章,但是讲心里话,前端优化的最终目的,难道不是为了改善用户体验吗?

任何基于用户体验的方案,都可以叫前端优化技术。

不管使用多么好的机器,响应速度问题总是避免不了的,因此纠结于什么技术来解决是不实际的。但是有一款好的工具,使用一些小技巧,也可以改善用户等待的体验。

比如,我们为每个非_target 的超链接或者表单的点击,添加点击事件处理,处理逻辑也很简单,就是设置 3 秒超时,显示等待对话框。如果在 3 秒内页面发生跳转,那么这个等待对话框就不会出现,否则会弹出提示用户等待,从而及时的将响应反馈给用户,减少用户空白等待时间。

这并不是什么高深的技术,但是运用这个技巧,却可以大大的改善用户体验。

我们优化的目的,就是不要让用户一直得不到响应,避免空白等待,让用户体验越来越好。


WordPress 全方位优化指南(下)