前言
标题无能,请各位看官放下你们的屠刀,扎心的往下看,看到情不自禁处请手下留情。
引言
您瞧清楚了,我是互联网公司技术开发一枚,渴了喝咖啡,饿了吃外卖,晕了上医院的那种。房贷没还清,车子自己买,人家休假我加班。还有最重要的是,我是一条单身狗。不要想着单身贵族这种身份,你爸和你妈的一巴掌就能让你认清现实。
我要讲的故事就四字:性能优化。
我知道,此时此刻看到这里的朋友一定会掌心出汗、眉头紧锁,用一种带着危险的眼神死盯着手机屏幕。来吧,我不怕。性能优化都没搞好,还想着去找对象?
我在前年遇到的面试题
面试官:你为性能优化做了哪些事情?
答: 懒加载
、缓存
、离线包
、并行化
面试官: 那离线包是如何设计的?
答: 就是将首页做一份快照,交给native童鞋在App打包的时候放入包的本地路径。
面试官:那你对懒加载或者缓存有什么具体的实施方案吗?
答: 有啊。骨架屏、SSR。
面试官: 骨架屏和SSR有什么各自优缺点?
答: 骨架屏适合在页面加载延迟毕竟高的情况下使用,但是骨架屏的灰色豆腐块需求视觉切图,这个图是需要缓存在客户端的。如果大范围使用骨架屏,可能会导致客户端缓存过多的图片,反而得不偿失吧。SSR实施成本会高一些,如果不是特别重要的页面不建议使用。 当网络环境很差劲的情况下,依然还是要做降级处理的,也就是客户端渲染。
面试官: 针对首屏白屏问题你有具体的解决方案吗?
我内心OS: 内心开始MMP了,合着我前面说的那些就不是解决方案了?
答: 方法有不少,但具体还是要看公司的环境了。毕竟不是所有手段都能用上。 但首屏很重要的一个点是做好缓存。例如利用好http缓存。。。
小结一下
那时候,面试几乎都是靠面试官抽一鞭子然后我回答一哆嗦。 回答性能优化方面的问题,也基本上是那老四样。 可问题就在于,这些答案换个人来也能说。说白了,你说出去的东西并不是真正属于你的东西。 然后,职位岗位略高一点,你就没机会了。
发生在昨天的面试故事
面试官:性能监控平台是如何搭建的?
答: 先确认性能指标。例如首屏渲染时间、页面白屏时间、秒卡率、FPS、平均请求时间等。
(被打断,因为面试官get到了他感兴趣的点)
面试官: 你们的 FPS
是怎么计算的?
答: FPS
(Frames Per Second
,每秒显示帧数)。一般 FPS
在 60
以上,页面流畅,不卡顿。但事实上并非如此,比如你在打游戏(例如吃鸡、王者荣耀),虽然 FPS 低于60
,但我们觉得很流畅,并不卡顿。
FPS 低于 60 并不意味着卡顿,那 FPS 高于 60 也非一定不卡顿。比如前 60 帧渲染很快(10ms 渲染 1 帧),后面的 3 帧渲染很慢( 20ms 渲染 1 帧),这样平均起来 FPS 为95,高于 60 的标准。这种情况会不会卡顿呢?明显是卡顿的。
所以卡顿与否的关键点在于单帧渲染耗时是否过长。
但难点在于,在浏览器上,我们没办法拿到单帧渲染耗时的接口。所以我们只能拿 FPS 来计算,只要 FPS 保持稳定,且值比较低,就没问题。我们给它定的标准是连续 3 帧不低于 20 FPS,且保持稳定。
(面试官眼睛开始有光了。)
面试官: 那你就写一下吧。
// **开始在线写代码。**
// 以h5 为例
/* 利用 requestAnimationFrame 在一秒内执行 60 次(在不卡顿的情况下)这一点, 假设页面加载用时 X ms,这期间 requestAnimationFrame 执行了 N 次, 则帧率为1000* N/X,也就是FPS。 */
/*但不同户客户端差异很大,需要考虑兼容性。 在这里我们定义 fpsCompatibility 表示兼容性方面的处理,在浏览器不支持 requestAnimationFrame 时,利用 setTimeout 来模拟实现。 在 fpsLoop 里面完成 FPS 的计算。 最后通过遍历 fpsList 来判断是否连续三次 fps 小于20。 */
const fpsCompatibility = function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
}
);
}();
const fpsConfig = {
lastTime: performance.now(), // performance 是一个浏览器提供的API
lastFameTime: performance.now(),
frame: 0
}
const fpsList = [];
const fpsLoop = function () {
const first = performance.now();
const diff = (first - fpsConfig.lastFameTime);
fpsConfig.lastFameTime = first;
const fps = Math.round(1000 / diff);
fpsConfig.frame = fpsConfig.frame + 1;
if (first > 1000 + fpsConfig.lastTime) {
const fps = Math.round((fpsConfig.frame * 1000) / (first - fpsConfig.lastTime));
fpsList.push(fps);
console.log(`time: ${new Date()} fps is:`, fps);
fpsConfig.frame = 0;
fpsConfig.lastTime = first;
};
fpsCompatibility(fpsLoop);
}
fpsLoop();
function checkFPS(fpsList, below = 20, last = 3) {
let count = 0;
for (let i = 0; i < fpsList.length; i++) {
if (fpsList[i] && fpsList[i] < below) {
count++;
} else {
count = 0
}
if (count >= last) {
return true
}
}
return false
}
checkFPS(fpsList);
// 如果连续判断 3次 FPS 都小于20,就认为是卡顿。
面试官: 嗯,可以。 那像这些性能指标的描述内容你们是如何上报的?
答:手动埋点
、自动化采集
、可视化埋点
面试官:如何设计一个性能SDK,有思路吗?
答: 性能SDK
设计,一个是接入
设计,另一个是SDK运行设计
。
- sdk接入设计
- 可以把之前首屏、白屏、卡顿采集的脚本封装进去。并让脚本自动运行。
- 做好SDK使用/帮助文档,提高易用性
- 整一个性能分析助手,能快速定位一些简单的基础问题
- SDK运行设计
- 兼容性问题,用原生JavaScript去写性能指标采集,实现跨端采集
- 容错机制,例如try catch捕获,然后把异常上报
- 测试sdk性能,可根据用户实际使用情况来确认机型分布
面试官: 你刚说的异常上报,你的上报策略是如何设计的?
答: 在采集性能指标后,最好还是先对数据异常进行过滤。不过上报策略设计,分几个部分吧。
- 日志数据过滤
- 先对数据异常进行过滤
- 异常数据包括计算错误,合法的异常值、最大值、最小值什么的。
- 数据抽样策略
- 上报的数据是全量还是抽样,需要根据日活来决定。
- 一般日活10W以下,可以选择全量。日活1000W的APP,那就需要抽样了。
- 上报机型选择
- 强网情况直接上报,弱网情况先将日志存储在本地,等待强网环境下再上报。
- 其它的还有APP启动时上报,批量数据上报等……
小结
约十次性能优化十次是什么鬼? 再约就是继续性能优化是什么鬼? 再后来的日子里,我还是和面试官们成为了朋友,困扰我很久的问题也终于从 “面试官们” 那得到了答案。
她是喜欢草莓味的咖啡奶茶,但她更想吃草莓味的冰淇淋。特价牌子的旁边就写着草莓冰淇淋的价格,而我却视而不见。人家指着那你都看不到,听到想点便宜的就暗自窃喜,你真当人家傻呢?
我把“她”换成“面试官”重新说一段。
面试官是喜欢问你对性能优化做了什么事情,但面试官更想知道你做到了而别人没做到的事情。老四样的旁边就写着适用于怎样的场景,而我却视而不见。人家指着那你都看不懂,听到想听简单的就暗自窃喜,你真当面试官傻呢?
所以,请相信,相亲从第一面就开始交锋了。先输了的那个往往就失去了主动权。如果你自嗨了,那你就失去了足够敏锐的观察力。人性都一样,对喜欢的东西容易不设防,对不喜欢的东西会倍加警惕。
最后,任何东西只要够深,都是一把刀。 性能优化也不例外。
(祝,君一切安好。)
今天的文章任何东西只要够深,都是一把刀(面试版)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23239.html