接单生涯 - 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 。

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

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

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

相关推荐
小阮的学习笔记7 分钟前
Vue3中使用LogicFlow实现简单流程图
javascript·vue.js·流程图
YBN娜8 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=8 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck12 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!33 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。38 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼1 小时前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning1 小时前
React.lazy() 懒加载
前端·react.js·前端框架