接单生涯 - No.1 JSP项目的性能优化

因为降本增效,我也在互联网圈激流勇退了,拿上亲爱的大礼包,高兴的告别同事,开始规划自己的下一段工作。

因为学历(普通本科)和不想刷八股的问题,工作年限也比较长了,大厂管理我是不太敢奢望了,但是久居人下亦非我所愿,索性就成立了一家公司 ------- 微谏科技。

公司成立好了,我也不能吃老本呀,所以就在接单平台(某客栈)逛了逛(非广告,体验不做评价,等我再用一段时间)。就碰见了我的第一位用户,他的诉求是页面目前加载要4, 5s,希望我能优化到2s内。

性能优化,这个话题老生常谈了,很多资料里对资源的压缩,请求的合并,懒加载,重复渲染的优化做了很详尽的描述,各种 performance 的差值计算,lighthouse 等监测工具的使用让人眼花缭乱,

初入门径的开发者跟着一顿操作,发现居然观感差不多。我之前在团队里也做过一段时间性能优化,简而言之,如果项目代码的写法没明显的性能问题,光靠资源压缩,加载,可能能让指标上去一点,但是让人的整体观感并不会有质的飞跃。

那本次,我是否能幸运的让项目性能飞跃起来呢,并得到用户支付的佣金呢,让我们开始正文吧!

1. 结构分析

我欣然接受后,打开了项目,项目如下。

jsp 复制代码
<html>
    <@include "path/commonJS.jsp" @>
    <@include "path/commonUploadJS.jsp" @>
    <body>
        <div>内容</div>
        <iframe src="path/iframe1.jsp" ></iframe>
        <iframe src="path/iframe2.jsp" ></iframe>
        <iframe src="path/iframe3.jsp" ></iframe>
        <iframe src="path/viewer.html" ></iframe>
        <script>
            // 各种变量定义;
            var a,b,c;
            // 各种ajax请求
            $.ajax(...);
        </script>
    </body>
</html>

2. iframe 懒加载

这个结构是从几千行的 jsp 代码中简化而来,咱们要做优化,主打的就是对一个页面的了解,看到简化后的页面,里面有多个 iframeiframe 会带来以下可能的性能问题。

  • 多个 iframe 会相互抢占下载资源
  • iframejs 阻塞会影响 父界面 的展示

在分析了 iframe 的作用后发现,有两个 iframe 在首屏是隐藏的,需要通过切换页面中的 Tab 才会将 display 切换为 block。所以这两位漏网之鱼就可以使用 iframeloading 属性一网打尽。这样这两个 iframe 既不会抢占下载资源,也不会占用解析 html,执行 js 的时间。

html 复制代码
    <iframe loading="lazy" src="path/iframeHidden" style="display:none"></iframe>

3. 优化白屏时间

解决上一个显而易见的问题后,让我们来关注下首屏时间,从上方示例可以看到,父页面首屏是有静态内容的,但是从实际情况看,要到一些 ajax 请求完成后,才能显示出来,这违背了我们的认知,ajax 不应该阻塞页面的渲染。

好在这些 ajax 都是在一个名为 init 的方法中执行的,我想着那就加一个 setTimeout 吧,这样肯定能让中间有空闲的时间,这样浏览器就会抓住机会渲染首屏了。

不出所料,当我把 setTimeout 放到 500ms 后,首屏确实提前渲染出来了。那小伙伴们肯定就有疑问了,为什么是 500ms 而不是 0ms,怎么去界定这个时间呢。

究其原因,是有一段框架的解析时间花了 400ms 左右,他是在 script 里直接执行的,且所有 script 都有部分写法可能依赖这个框架的解析。对于一个历史大项目来说,框架的写法无法去做改动,影响面太大,暂不做讨论。

如果说咱们 setTimeout 放到 200ms,框架解析完就会立马执行这个 setTimeout,浏览器还是没有得到喘息的机会,白屏时间还是很长。

但是这个方法有一个漏洞,就是调试的电脑,框架平均解析时间是 400ms,有没有可能别的电脑很快,200ms 就做完了,那就白白浪费了 300ms 。接着我想到了一个好办法 requestIdleCallback。这样我们就不用管到底该等多久了,浏览器自己会去处理好的。

4. ajax 还能阻塞页面?

上面的方式取巧的解决了首屏的渲染问题,但始终有一团疑问在心头,ajax 为什么会阻塞页面渲染,仔细看了此处代码后恍然大悟。

js 复制代码
    function getData() {
        var data;
        $.ajax({
          url: '/path/api',
          async: false,
          onSuccess: function(res) {
            data = res;
          }
        });
        return data;
    }
    
    var a = getData();

注意看,这里用到了一个属性 async 值为 false,这就是阻塞页面的元凶,它会让我们创建的 xhr 不太机灵。从 MDN 上也有相关的描述。

由于客户此处链式调用接口有多个,且依赖上一个接口的输出结果,所以如果优化为异步的,需要业务人员的介入了,暂时先给客户记着。

5. 大型第三方库的执行时间

很多 toB 的应用都要选用一些大型的第三方库,本次这个项目也不例外,因为需要做 excel 相关的功能,所以客户采购了 SpreadJS ,是一个做 Web Excel 很出名的库,能把 js 库做成付费产品,也能看出还是有一番实力的。

功能的强大也就意味着初始化的时间会更长,用性能观测发现大概需要 500ms 左右,但客户的需求是2s 总共也没几个 500ms,更换库也是不现实的,大量业务代码是基于这个库的。

目前我对脚本的加载做了 defer,就是不想让 excel 的渲染阻塞其他元素的渲染,让页面除 excel 以外的区域能够更快的展示。对整体加载时间影响不大。

但是不知道是不是调整加载顺序的影响,使用 defer + $(document).ready(function(){}) 后,打开 excel 速度提升了 200ms

对于这个库还有个优化思路,就是要将业务中用 excel 的功能模块划分清楚,轻量的话,只加载一个主js,按需去加载相应的插件,这样会让加载时间和执行时间都缩短一些。这个也需要业务人员耗费精力去梳理才能做到。

6. GZIP & HTTP2.0

lighthouse 上指标还是比较明显的,实际观感不大,可能是因为有浏览器缓存,所以加载时间对整体的影响不大,对首次打开的用户会有一些帮助。

7. 结局

最终页面打开速度来到了 3s 左右,未达到客户预期,白屏优化客户还是比较满意的。看在我辛苦的份上,客户也是发来了让我期盼已久的回应。

优化是在自己的空闲时间做的,大概总时长是 12 个小时左右(4天,每天3小时左右),收获 1000 元,刨除平台扣除,剩余 800 。

除了金钱的收益外,还有两点潜在的收益,也还是蛮不错的

  • 认识了一位客户,且给客户留下印象不错
  • 加深了自己对性能优化的理解

这就是整个故事的经过啦,对更详细的过程有兴趣的朋友,可以私信一下,我知道的都会尽量告诉你们哒。如果文章对你有所帮助,帮忙点个赞,感谢路过的朋友的支持。

相关推荐
旧味清欢|3 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
热爱编程的小曾20 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin32 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox44 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员