#####一.前言 本文的上一篇 JavaScript 踩坑心得— 为了高速(上) 主要和大家分享的是 JavaScript 使用过程中的基本原则以及编写过程中的心得分享,本文主要和大家聊聊在各个使用场景下的 JavaScript 使用,以及在性能优化方面的优化经验等
#####二.各种场景下的 JavaScript ######1.用于 UI 应用的 JavaScript 与大多数服务器端语言一样,用于客户端应用的 JavaScript 框架从来就不缺少。然而,和用在后端应用与服务中一样,笔者偏好使用较小的模块,将这些小模块组合为框架,从而实现可扩展性,可维护性以及较高的重用度。
并且,由于小模块的特性,后期拍错或者进行性能优化的时候也会非常方便,现在国内外针对前端 JavaScript 的性能行为分析工具也比较成熟了,例如 Browser Insight、APPdynamic、Ruxit,都是不错的选择
######2.构建 Web 应用的 JavaScript 对于 Web 应用,笔者发现将 React 用于实现 UI,Redux 用于状态管理,Joi 用于数据验证,是建立可扩展客户端应用的最有效技术基础。这样建立起来的应用,往往易于操纵,测试以及调试
笔者非常喜爱该组合的一点,是他们使得遵循「 JavaScript 的两大支柱」变得更加简单。从 0.14 版本开始,React 增加了对纯函数的支持,Redux 也使用了纯函数与可组合的 reducers。看来,使用典型面向对象模式的脆弱应用已经一去不复返了。
该组合的另一大优点是可用的工具很多。React 与 Redux 都有 Chrome 开发者工具插件,使得调试与操作应用变得极为简单。而诸多支持模块,比如 React Hot Loader 与 Webpack 也使得反馈更加及时。笔者建议你仔细了解一下这两个模块。
######3.构建移动应用 显而易见,如果是构建移动平台的应用,笔者肯定会推荐 React Native。目前,React Native 仅支持 iOS 与 Android 平台,因此,除非你真的需要 Windows 支持,笔者会统一推荐 React Native。
还有一个值得一说的就是,现在无论安卓还是 ios 的 APP 性能优化 也非常重要,但是很多公司只注重后端架构、代码质量等问题,却忽视了前端编写时可能存在的影响因素。并且,尽管 JS 测试对于确保应用如期运行非常重要,但人们却也常常在测试中花去太多时间,并不是说不应该编写测试代码,只是,要小心过度测试与过度模拟,所以上文提到过的 Browser Insight、newrelic、APPdynamic 等真心都是优化前端不错的选择。 #####三.测试用 JavaScript ######1.仅测试公共 APIs 通过不专注于内部程序,只要不破坏模块内的公共 API,我们就能随心所欲地改变他们。这意味着,测试的变化无需那么频繁,而且你可以确保自己接收的数据正是应该收到的数据。
######2.建立测试框架 说到实际应用的测试模块,笔者最近迷上了 tape 与 nock。有了这两个模块,笔者就能覆盖 99% 的测试(有时候,笔者必须自行监控一些数据,并使用 Sinon)。Browser Insight 这款产品无论是线上还是线下,针对前端页面的 JS 错误都能准确的定位到,精确到代码行,非常方便。
######3.测试用户体验(UX) 如果你在打造 Web 应用,可能会想在尽可能多的设备与浏览环境下测试用户体验。为了获得更为直接的反馈,笔者采用了 Browser Insight,这个工具的好处就是基于真实的用户体验,多维度的定位分析网站的性能问题,例如脚本错误、ajax调用、响应时间分布等板块,而且,这个工具支持 PC 端、移动浏览器、移动微信页面、APP 等多个使用场景,基本上能满足绝大多数场景的使用需求。
#####四.JavaScript 性能优化误区 ######1.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 优化的问题,因为它具有避免加载不必要模块的功能,结果反而南辕北辙。
根据 大功能来划分模块 也是一个不错的尝试。
笔者尝试将所有模块划分为 基础模块 和 功能模块 ,基础模块包括页面头部,尾部相关的公共部分,功能模块则根据前后台划分,前台部分,又根据具体的页面来划分,能合并到一起的,就合并成一个模块,增加粒度。结果 JavaScript 文件减少,也达到了预期的效果。
从实际体验来看,对于流量不大的网站来说,没有必要使用懒加载 JavaScript 的相关技术,因为本身 JavaScript 文件就不是非常大。因此在网页加载时,就可以先加载所需要的模块。避免不必要的延迟。
######2.JavaScript 的位置问题
这一部分,我们来说说 JavaScript 的位置问题对网页网站性能的影响。
为什么要考虑位置问题?
其实不管是 CSS 还是 JavaScript,都需要考虑位置的问题,因为 HTML 的渲染和加载顺序是从上往下,也就是如果前面插入了 JavaScript 的引用,那么必须等到这个 JavaScript 下载完毕才会渲染后续的部分。
因此 JavaScript 的插入位置就成为一个值得考虑的问题,因为不适合的位置可能引起渲染的延迟等,造成不好的用户体验。
传统方案带来的问题和思考
CSS 放在头部,JavaScript 放在尾部,这是传统的经验,它的好处是可以让页面优先渲染, 从而页面可以快速显示。
但有事实往往没有我们预想的那么美好。
有的时候会出现这么一种情况:当页面已经渲染完毕时,我们立刻去使用网站的功能,但很多时候 功能按钮会没有反应。原因也很简单,就是 JavaScript 放在页面的尾部,还没来得及加载。。。。
这就纠结了。。。。
两种 JavaScript 放置方式,一种放在头部,一种放在尾部(暂时忽略部分放在头部,部分放在尾部的方式),一个牺牲了渲染速度,一个牺牲了用户体验。所以很多时候 js 的问题我们需要做权衡。
对一般的小型网站来说,用户体验问题要远远大于页面渲染的问题,就比如上文提到的那种功能按钮不可用的情况。而且,如果 JavaScript 不是很大的话,放在头部就很好,既不会有太久的页面空白,也能让其优先加载,二者得到了很好的平衡。
因此,很多经验上的东西并不是绝对的,一定要根据实际的情况,包括功能特点、服务器网络情况等来综合考虑。
为此,笔者写下一个自认为较为合理的位置选择方案,仅供参考。
图 1. 判断 JavaScript 放置位置决策表
从上面的分类介绍,我们也可以看出,将功能代码按类型归类到不同的 JavaScript 文件是多么的重要,比如应该放头部和应该放尾部的代码,最好不要合并在一起,不要等到出问题要优化的时候再去整理和重构,这样会增加很多不必要的工作量。
这不仅仅是为自己工作负责,也是为后面要读你代码的新人负责。养成好的设计编码习惯,也是技术积累的一部分。最后再根据 JavaScript 文件的功能类型,来决定是放在页面的头部还是尾部。
#####五.怎样确定是不是 JavaScript 的问题? 这个问题笔者在之前看过的的前端高性能优化(一)、(二)中 get 到了新的技能点,在这里分享给大家。
随着信息爆炸时代的到来,网站本身性能也深刻影响着公司的形象、利益等问题。但是大多数前端测试工具都太碎片化,没有办法针对多个使用场景,而且很多都是像 yslow 这样简单打个分,也不是真实的用户体验。前一段时间在网上找到了一款前端性能优化分析工具——Browser Insight,里面的功能相当全面,而且可以针对多个使用场景,包括:PC端,移动微信,移动浏览器,移动webview,还是 真实的用户体验,也就是说,用户访问你的网页是什么样的,从这个工具中体现出的就是什么样子的。
基于 JavaScript 这个维度 Bi 做的也是相当丰富了。
首先是 脚本错误 板块。Bi 里面可以从不同的时间维度查看被监控页面出现过的脚本错误,具体信息包括:发生时间、设备类型、报错的浏览器及其版本号、错误堆栈信息都可以看到,不论是 线上还是线下测试或者页面维护 都是够用了。
不但能看到时间、系统、浏览器等,还可以具体定位到出错的代码行,这个确实很方便。
图 2.Bi 脚本错误
其次是页面响应时间板块,这个算是意外的收获了。通过响应时间板块里面的慢加载追踪,可以看到本次慢加载的页面资源加载情况,然后我们就知道该优化哪个页面的哪些 js 、css、img等。
图 3.Bi 资源列表-时序图
#####六.结语 JavaScript 具备许多独特的优势,笔者甚至敢说,JavaScript 很可能是目前最重要的语言,因为它能在几乎所有平台上运行,而且可以通过高度可重用、可组合的方式实现。
然而,不熟悉 JavaScript 性能与问题的开发者可能很快就会发现,对其代码库进行更改变得越发困难,而且这些改变可能会导致出其不意的逆反效果。
笔者建议,不要像用其他语言写程序那样编写 JavaScript 程序。尽可能利用 JavaScript 独有的性能,创建小而简单的模块。这有助于你保持冷静,并爱上 JavaScript 的强大功能。
Happy JavaScripting!
**注:**本文翻译自 Kurtis Kemple 的一篇文章,由小编加了一些自己的意见和看法。
原文地址:https://labs.mlssoccer.com/javascript-at-scale-achieving-high-velocity-160c7d78af03#.egfwqqz0a
Browser Insight 是一个基于真实用户的 Web 前端性能监控平台,能够帮大家定位网站性能瓶颈,网站加速效果可视化;支持浏览器、微信、App 浏览 HTML 和 HTML5 页面。想阅读更多技术文章,请访问OneAPM 官方技术博客。
本文转自 OneAPM 官方博客