日常工作开发中,遇到哪些坑是让你印象深刻且具有挑战的,它们是怎么产生的,我们该如何避免?本期我们带来与前端开发相关的三个问题:一次网页资源加载问题的定位过程;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];// 大于1sif (timing.duration > 1000) {slowList.push(timing);}
}
send(slowList);

上报信息也包含了每个请求的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标签加载图片,可以快速获取:

// 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:;

  • 继承: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影响时,固定定位元素的包含块是根元素,可以近似认为是元素,因此fixed元素可以实现相对视口定位的效果。而当元素设置了transform时,便会创建一个新的包含块(containing block),如果该元素的内部有元素设置了fixed定位,那么该fixed元素的包含块便不再是根元素,而变成了被设置了transform的元素。如果在开发过程中发现设置了position:fixed的元素随着页面滚动了,就可以看下fixed的元素外层是否有元素设置了transfrom。

除了包含块之外,transform还会生成新的层叠上下文(stack context),使得元素内部和外部的z-index相互独立,出现低z-index元素层级比高z-index元素还高的情况:

推荐阅读

百度工程师教你快速提升研发效率小技巧

百度一线工程师浅谈日新月异的云原生

【技术加油站】揭秘百度智能测试规模化落地

【技术加油站】浅谈百度智能测试的三个阶段

百度程序员开发避坑指南(前端篇)相关推荐

  1. 百度程序员开发避坑指南(3)

    前两期我们分享了日常工作中前端.移动端开发的相关问题,感兴趣的同学可以在文末推荐阅读跳转查看.本期我们分享三个议题:golang对象池减少gc压力.FFmpeg中的并发控制.paddle的静态图和动态 ...

  2. Python程序员的“避坑”指南

    结合我最近这些年的Python学习.开发经验,发现90%的人在学Python时都会遇到下面这些问题: 1. 没什么经验根本不知道从何学起,而且应用方向太多了根本不知道该选择什么方向... 2. 基础入 ...

  3. FlyFish|前端数据可视化开发避坑指南(二)

    FlyFish是云智慧开源的一款数据可视化编排平台.通过配置数据模型为用户提供上百种可视化图形组件,零编码即可实现符合自己业务需求的炫酷可视化大屏. 同时,FlyFish也提供了灵活的拓展能力,支持组 ...

  4. HarmonyOS 开发避坑指南

    Harmony OS 开发避坑指南--源码下载和编译 本文介绍了如何下载鸿蒙系统源码,如何一次性配置可以编译三个目标平台(Hi3516,Hi3518和Hi3861)的编译环境,以及如何将源码编译为三个 ...

  5. 小程序进阶之路:跨平台开发避坑指南

    阿里妹导读:小程序的开发不可避免的会面临跨平台开发的问题.各小程序平台有哪些特点?如何处理各平台的差异?本文分享淘票票在跨平台开发上的经验总结,包含了技术演进及差异控制策略,希望能帮助同学们提前避坑. ...

  6. 前端程序员开发技术栈(前端干货)

    网上找的各种资料整理归纳成下面的表格,有需要的朋友们可以收藏一下 Web前端开发 浏览器 (直接百度下载使用就行) Internet Explorer(需要了解,需不需要看公司业务需求)     Ch ...

  7. 抖音开放平台基础开发避坑指南

    抖音小程序开发基础避坑 自定义组件路径,引用到具体的组件上 //相对路径引用到具体的组件上"usingComponents": {"intro-box":&qu ...

  8. ae导出json_关于AE转json动画开发避坑指南

    本篇文章是给一定基础的UI设计写的 Lottie 是Airbnb开源的一个面向Android. iOS.React Native .Web的动画库,能分析 Adobe After Effects 导出 ...

  9. 五种糟糕的代码实践,程序员注意避坑

    本文将向你展示五种糟糕的代码实践,它们足以让所有程序员深恶痛绝. 1将变量命名变成解谜游戏 图译:parseDBMXML 代指什么:A.解析 DBM XML .B.解析 DB MXML.C.解析 DB ...

  10. java类中的代码块,Java开发避坑指南!

    一.阿里 (会员中台) 1. Java 重写hashcode()是否需要重写equals(),不重写会有什么后果 2. 并发 自旋锁和阻塞锁的区别 公平锁和非公平锁的区别 jdk中哪种数据结构或工具可 ...

最新文章

  1. netty做一个posp的网络_皑云网络——接手一个新的SEM竞价账户怎么做?
  2. java反射机制--reflection
  3. U3D开发中关于脚本方面的限制-有关IOS反射和JIT的支持问题
  4. 数据结构的简单理解(4)
  5. python输入法引擎_Bigram-MLE语言模型和模拟输入法的python实现
  6. C++中如何定义动态数组
  7. Java 三大特性之——继承
  8. 论文笔记 - 《Very Deep Convolutional Networks For Large-Scale Image Recognition》 精典
  9. 浅谈NB-IoT应用场景及方案
  10. Net-snmp开发流程:MG-SOFT套件生成C语言snmp set/get代码
  11. Android 获取手机的厂商、型号、Android系统版本号、IMEI、当前系统语言等工具类...
  12. 欺诈与反欺诈的旷世攻防之战
  13. 软件质量保证与测试(什么是图灵测试)
  14. 深信服桌面云的各种密码
  15. 织梦dede采集文章
  16. 地质勘查土质分类图片_土的工程地质分类及各类土的工程地质性质.pdf
  17. [POI2008]Mirror Trap
  18. Linux手机DIY.夏新E600和飞利浦968的重大突破
  19. 苹果笔记本接移动硬盘怎么使用
  20. hadoop开发环境配置

热门文章

  1. 基于FPGA打地鼠游戏的设计与实现
  2. html修改progress背景色,html5progress标签如何更改进度条颜色?progress进度条详解
  3. 服务器被黑客入侵了怎么办?
  4. java项目第12期-淘客系统源码(安卓+IOS+java后端)【毕业设计】
  5. 功率因数 matlab,基于MATLAB的有源功率因数校正器设计
  6. Python生成 一维条码
  7. C#桌面办公应用-工资管理系统系列二
  8. 十月美剧精听总结 - 权力的游戏「Game of Throne」 黑袍纠察队「The boys」 老无所依「No Country for the old men」
  9. Intel(R) Ethernet connection (2) I219-LM 设置抓取VLAN tag报文
  10. linux怎么查看root权限,linux 查看当前用户是否有root权限490