百度程序员开发避坑指南(前端篇)
日常工作开发中,遇到哪些坑是让你印象深刻且具有挑战的,它们是怎么产生的,我们该如何避免?本期我们带来与前端开发相关的三个问题:一次网页资源加载问题的定位过程;CSS 中的 z-index 层叠覆盖问题;CSS3 transform 属性对 position 的影响,希望能为你的技术提升助力。
01
一次网页资源加载问题的定位过程
今天讨论的话题比较聚焦,就是有用户报 Web 页面资源或局部区域加载不出来的问题,该如何查?又该如何避免?
1.1 问题描述
用户反馈页面内的推荐列表加载不出来,而且能稳定复现。
1.2 分析
第一反应就是自己复现,但是不行啊,团队没有同学能复现,也无法接触到用户。那么先理清楚此区域的实现逻辑,该区域的 HMTL 虽然已经下载,但默认不可见,而是依赖 c.js(文件名简化了)展现。基于此,我们怀疑:
c.js 以及其依赖的 a.js, b.js 等 加载非常慢或直接失败;
c.js 以及其依赖逻辑发生 JS 异常。
1.3 监控实现
那么该如何佐证,我们需要做下监控。
做监控需要考虑到实际场景,由于 Head 和 Body 都有外链请求,因此监控代码要置于顶部且内联,且代码要精简,从而可以最大程度拿到信息和减少首屏影响。
上述可以监控到全局的 资源加载失败 和 JS 异常,包括未捕获的 Promise Rejection。此外,还需定位资源,通过向上遍历获取元素的 XPath,XPath 上带上 id 或 class 属性,避免全都是`div>div>div>div`,而摸不着头脑。
上线后发现,有不少错误都是 script error,这是因为外链 JS 都是 CDN 域名。浏览器对于脚本执行遵守 same-origin policy ,为避免域名信息泄漏给宿主域名,特意隐藏错误信息。
解决方案是给所有外链 JS 加上响应头。
JS 资源若托管在云上 CDN 服务,那么其 CDN 控制台都会提供增加 Header 功能。
若是自有服务,就需要主动设置 Header。这里假设使用 Koa2 框架,设置如下:
然后给所有该 CDN 域名的 script 元素增加 crossorigin 属性,如:
但发现其在 Chrome 浏览器是生效的,可以拿到真实错误堆栈。可惜,Safari 浏览器不支持此机制,依然只能拿到 script error。为了 Safari 拿到真实错误,外链需要是同域。因此有个办法是在 www.a.com 的 Nginx 做一层代理转发,即 https://www.a.com/static/a.js 转发到 https://cdn.a.com/static/a.js 。不过如此一来,就丧失 CDN 就近访问的优势,不适合常态化。但可以在定位用户问题时,将用户访问临时切换成 https://www.a.com/static/a.js。
那如何监控加载慢,可以在 onload 事件后获取慢资源。
上报信息也包含了每个请求的 TCP、下载等耗时,详细可见 Resource_Timing_API 规范(https://developer.mozilla.org/en-US/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API)。
要注意的是,该 API 信息受到 CORS (https://developer.mozilla.org/en-US/docs/Glossary/CORS)影响,必须给资源设置如下响应头才能拿到数据,否则很多字段取值都是 0。
Timing-Allow-Origin: *
通过分析这些数据,我们可以知道资源耗时过程,这里可以充分参照 Chrome 开发者工具提供的 Timing 子面板,了解关键时段耗时。比如同域名 6 个并发请求限制,若资源请求较多,则可能处于 stalled(挂起等待)状态。这些阶段可能原因分析参考 Chrome 说明。
由于有些图片在页面内不好确定位置,因此需要获取其 XPath,如何获取呢?对于 img 标签加载图片,可以快速获取:
额外信息获取,其实除了问题信息本身外,用户当时环境信息非常重要,如
1. performance.memory:获取内存使用信息;
2. navigator.connection:用户连接情况,可惜,此 API 不怎么准;
如果是 APP 内页面,可以调用端能力获取到用户网络类型、网速。
1.4 数据分析
上线后,用户依然访问慢。根据日志发现,用户未有 JS 报错,但根据慢资源日志,发现有大量资源加载超过 1s,有些资源甚至达到 10s,其花费在建连阶段耗时较大。看来问题还不是这么简单,那如何解释用户资源加载如此慢?用户所在局域网环境差?接入运营商质量差?插件影响?CDN 问题?
这些问题只有 CDN 可以去排查,我们首先拿到用户访问 https://www.a.com 的服务器端日志,获取到用户 IP。联合云 CDN 服务,根据用户 IP,竟然未查到任何 CDN 访问日志。但从日志看,用户确实请求了大量 JS,并不是全部本地缓存。所以用户 IP 可能不是访问 CDN 的 IP,有一种情况是使用代理。
所以想通过其他信息捞取用户的 CDN 日志,来确定访问 CDN 的 IP。思路是按照用户 UA、请求地址等非精确信息捞取 CDN 日志,但由于捞取日志量非常大,无法确定哪些日志是该用户的;而:
1.CDN 域名一般是无 cookie 域名,没有 TRACEID;
2.Web 页面无法给 script/link 资源请求头设置 Traceid;
3.前端目前无法拿到 CDN TCP 建连 IP;
综上,除了用户 IP,种种精确定位信息都无效。因此这一步举步维艰。
好在能联系上用户,咨询是否使用代理,结果:确实使用了代理,且根据用户代理,实测代理非常慢,甚至加载超时,其代理请求走了香港服务器。通过代理出口 IP,最终从海外 CDN 捞取到了用户访问日志。同时也确认,用户将所有 *.a.com 请求配置不使用代理,所以服务端能拿到的 IP 是用户 IP,而 CDN 拿到的是代理出口 IP。
1.5 总结
Web 能力终是有限,但通过足够的辅助信息,以及全链路协作,在定位 Case 过程中也会事半功倍。该 Case 虽然归因于用户不合理代理配置,但也可基于此场景做技术优化。如任何首屏内容不依赖外链展现,减少核心逻辑 JS 体积,增加资源缓存率等。
02
CSS 中的 z-index 层叠覆盖问题
2.1 含义
z-index 属性指定了元素及其子元素的【z 顺序】,而【z 顺序】可以决定当元素发生覆盖的时候,哪个元素在上面。通常一个较大的 z-index 值的元素会覆盖较低的那一个。
属性指定两件事:
当前元素的堆叠顺序
当前元素是否建立新的堆叠上下文
2.2 属性值
默认值:z-index:auto;
整数值:z-index:<integer>;
继承:z-index:inherit;
2.3 基本特性
在 CSS2.1 时代,需要和定位元素配合使用;
如果定位元素 z-index 没有发生嵌套(并列的):
后来者居上的准则;
哪个大哪个上(z-index 大小比较);
如果定位元素 z-index 发生嵌套:
祖先优先原则(前提:z-index 是数值,不是 auto)
以上为 z-index 的基本介绍。
当业务越来越复杂,多种弹窗、toast、浮层各种组件,多人协同业务开发的情况下:
老业务写了个 z-index:5000;
B 同学调用一个全局弹层,原本设置为 100,想要覆盖全局,z-index 改为 10000;
C 同学调用一个 toast,原本设置为 2000,想要覆盖弹层,z-index 改为 100000;
...
层层覆盖的情况下,不能无限改下去,为了避免这样的情况发生,减少不断覆盖的情况,那么应该如何规定 z-index 的值呢;
**注意:**还是要规范 z-index 的配置,不要乱用滥用随意赋值,根据依赖规则合理使用;
03
CSS3 transform 属性对 position 的影响
CSS3 中引入了 transform,定义了在二维或三维空间中元素的旋转、缩放、平移等行为,还能利用合成层原理开启 GPU 加速,提升页面动画的流畅度。然而 transform 也不是「省油的灯」(并没有说它不好的意思,我就很喜欢它),增强了页面交互效果的同时它也有一些「副作用」容易让人踩坑。
position: fixed 实现了固定定位的效果,元素不追随滚动条进行滚动,普通元素的 overflow 属性也无法对其进行裁剪,因此在一些需要固定头部、固定悬浮按钮的场景中十分好用。
但 fixed 遇上 transform 时表现的就不再那么「强硬」,反而退化成了 position: absolute 的效果。在外层没有 transform 影响时,固定定位元素的包含块是根元素,可以近似认为是<html>元素,因此 fixed 元素可以实现相对视口定位的效果。而当元素设置了 transform 时,便会创建一个新的包含块(containing block),如果该元素的内部有元素设置了 fixed 定位,那么该 fixed 元素的包含块便不再是根元素,而变成了被设置了 transform 的元素。如果在开发过程中发现设置了 position:fixed 的元素随着页面滚动了,就可以看下 fixed 的元素外层是否有元素设置了 transfrom。
除了包含块之外,transform 还会生成新的层叠上下文(stack context),使得元素内部和外部的 z-index 相互独立,出现低 z-index 元素层级比高 z-index 元素还高的情况:
推荐阅读:
评论