共计 4965 个字符,预计需要花费 13 分钟才能阅读完成。
日常工作开发中,遇到哪些坑是让你印象粗浅且具备挑战的,它们是怎么产生的,咱们该如何防止?本期咱们带来与前端开发相干的三个问题:一次网页资源加载问题的定位过程;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 都有外链申请,因而监控代码要置于顶部且内联,且代码要精简,从而能够最大水平拿到信息和缩小首屏影响。
window.addEventListener('error', event => {if (event.srcElement !== window) {console.log('资源加载失败,加载资源的元素是:', event.srcElement);
send();}
else {console.log('JS 报错:', event.message);
send();}
}, true);
window.addEventListener('unhandledrejection', event => {const error = event.reason || {};
console.log('JS 报错:', error);
send();});
上述能够监控到全局的 资源加载失败 和 JS 异样,包含未捕捉的 Promise Rejection。此外,还需定位资源,通过向上遍历获取元素的 XPath,XPath 上带上 id 或 class 属性,防止全都是 \`div>div>div>div\`,而摸不着头脑。
上线后发现,有不少谬误都是 script error,这是因为外链 JS 都是 CDN 域名。浏览器对于脚本执行恪守 same-origin policy,为防止域名信息透露给宿主域名,特意暗藏错误信息。
解决方案是给所有外链 JS 加上响应头。
access-control-allow-origin: *
JS 资源若托管在云上 CDN 服务,那么其 CDN 控制台都会提供减少 Header 性能。
若是自有服务,就须要被动设置 Header。这里假如应用 Koa2 框架,设置如下:
ctx.set('Access-Control-Allow-Origin', '*');
而后给所有该 CDN 域名的 script 元素减少 crossorigin 属性,如:
<script src="https://cdn.a.com/static/a.js" crossorigin="anonymous"></script>
但发现其在 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 事件后获取慢资源。
const list = performance.getEntriesByType('resource');
const len = list.length;
const slowList = [];
for (let i = 0; i < len; i++) {const timing = list[i];
// 大于 1s
if (timing.duration > 1000) {slowList.push(timing);
}
}
send(slowList);
上报信息也蕴含了每个申请的 TCP、下载等耗时,具体可见 Resource\_Timing\_API 标准(https://developer.mozilla.org…\_Timing\_API/Using\_the\_Resource\_Timing\_API)。
要留神的是,该 API 信息受到 CORS(https://developer.mozilla.org…)影响,必须给资源设置如下响应头能力拿到数据,否则很多字段取值都是 0。
Timing-Allow-Origin: *
通过剖析这些数据,咱们能够晓得资源耗时过程,这里能够充沛参照 Chrome 开发者工具提供的 Timing 子面板,理解要害时段耗时。比方同域名 6 个并发申请限度,若资源申请较多,则可能处于 stalled(挂起期待)状态。这些阶段可能起因剖析参考 Chrome 阐明。
因为有些图片在页面内不好确定地位,因而须要获取其 XPath,如何获取呢?对于 img 标签加载图片,能够疾速获取:
// timing.name 就是资源地址,适宜
const img = document.body.querySelector('img[src="' + timing.name + '"]');
const xpath = getxpath(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 的值呢;
const KEY = '_tbv_z_index_';function initZIndex$() { return (window[KEY] = 10000);}// 初始化,只能被调用一次 function once(fn) {const flag = true; return function () {if (flag) {flag = false; const args = Array.prototype.slice.call(arguments, 0); fn.apply(args); } };}const initZIndex = once(initZIndex$);// 内部调用 & 反对重置 function zIndex$(zIndex) {if (zIndex) {return (window[KEY] = zIndex); } return (window[KEY] += 1);}// 组件 mount 时触发 +1const zIndex = zIndex$();
留神: 还是要标准 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 元素还高的状况:
举荐浏览 :
百度工程师教你疾速晋升研发效率小技巧
百度一线工程师浅谈突飞猛进的云原生
【技术加油站】揭秘百度智能测试规模化落地
【技术加油站】浅谈百度智能测试的三个阶段