JavaScript 踩坑心得— 为了高速(下)

Stella981
• 阅读 523

#####一.前言 本文的上一篇 JavaScript 踩坑心得— 为了高速(上) 主要和大家分享的是 JavaScript 使用过程中的基本原则以及编写过程中的心得分享,本文主要和大家聊聊在各个使用场景下的 JavaScript 使用,以及在性能优化方面的优化经验等

#####二.各种场景下的 JavaScript ######1.用于 UI 应用的 JavaScript 与大多数服务器端语言一样,用于客户端应用的 JavaScript 框架从来就不缺少。然而,和用在后端应用与服务中一样,笔者偏好使用较小的模块,将这些小模块组合为框架,从而实现可扩展性,可维护性以及较高的重用度。

并且,由于小模块的特性,后期拍错或者进行性能优化的时候也会非常方便,现在国内外针对前端 JavaScript 的性能行为分析工具也比较成熟了,例如 Browser InsightAPPdynamicRuxit,都是不错的选择

######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 InsightnewrelicAPPdynamic 等真心都是优化前端不错的选择。 #####三.测试用 JavaScript ######1.仅测试公共 APIs 通过不专注于内部程序,只要不破坏模块内的公共 API,我们就能随心所欲地改变他们。这意味着,测试的变化无需那么频繁,而且你可以确保自己接收的数据正是应该收到的数据。

######2.建立测试框架 说到实际应用的测试模块,笔者最近迷上了 tapenock。有了这两个模块,笔者就能覆盖 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 文件的功能类型,来决定是放在页面的头部还是尾部。

#####五.怎样确定是不是 JavaScript 的问题? 这个问题笔者在之前看过的的前端高性能优化(一)(二)中 get 到了新的技能点,在这里分享给大家。

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

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

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

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

图 2.Bi 脚本错误 JavaScript 踩坑心得— 为了高速(下)

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

图 3.Bi 资源列表-时序图 JavaScript 踩坑心得— 为了高速(下)

#####六.结语 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 官方博客

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这