学会了这招,排查生产问题再也不头疼了
点击小卡片参与粉丝专属福利
背景上周遇到一个生产问题,有一个页面底部有个分享按钮,在生产环境不显示。而同样的代码,在测试环境却是正常的。如下图所示,左边是生产的,右边是测试环境的。
这是为什么呢?心中带着困惑,开启了破案模式。
初步确定嫌疑犯先确定一下是不是定位样式引起的问题,之前发生过在IOS12版本手机上,fixed定位显示有问题,导致元素在页面不展示。对比查看了一下测试环境和生产环境渲染之后的页面dom元素,发现生产环境页面底部的分享按钮不显示,是因为dom元素未满足渲染。而非定位样式问题。嫌疑犯已经基本确定。
通过查看源代码,我们猜测一下嫌疑犯的作案过程。相关的代码片段如下:
ActivityFooter
v-if="isShowFooter"
:staffId="staffId"
:activityFooterInfo="state.bannerImageInfo"
@share="shareShow"
/
isShowFooter控制底部按钮的显示隐藏,跟isShowFooter相关的变量有三个,分别是state.isChat,state.bannerDetail?.shareSidebar, state.bannerImageInfo?.id。这三个变量初始化之后,会发生改变的代码片段如下:
conststate=reactive({
bannerDetail:{}asIBannerDetail,
bannerImageInfo:{}asIBannerImageInfo,
isChat:false,//侧边栏进入
constisShowFooter=computed(()={
return!(state.isChat!state.bannerDetail?.shareSidebar)state.bannerImageInfo?.id;
state.isChat的值改变逻辑是:
wx.invoke('getContext', {}, (res: TRes) = {
console.log('%c res:', 'color: #0e93e0;background: #aaefe5;', res);
if (res.err_msg === 'getContext:ok') {
const entries = ['single_chat_tools', 'group_chat_tools', 'chat_attachment'];
state.isChat = entries.includes(res?.entry);
} else {
// 错误处理
console.log('getContext error', res);
}
});
在控制台打印输出res?.entry,可以看到取值是normal,那么state.isChat的最终值应该是false。
image.pngstate.bannerDetail的值改变逻辑是:
constdetailRes=awaitbannerApi.getBannerDetails({longId:bannerId,staffId:staffId
state.bannerDetail=detailRes.retdata?.detail;
抓包查看接口的响应数据是:
image.png那么state.bannerDetail?.shareSidebar的值应该是true。
state.bannerImageInfo的值改变逻辑是:
constbannerImageInfoRes=awaitbannerApi.getBannerInfo({bannerId:bannerId,staffId:staffId
state.bannerImageInfo={...bannerImageInfoRes.retdata
抓包查看接口的响应数据是:
image.png所以state.bannerImageInfo?.id的值是44。
因为isShowFooter的计算表达式为:
constisShowFooter=computed(()={
return!(state.isChat!state.bannerDetail?.shareSidebar)state.bannerImageInfo?.id;
});
这么计算下来,isShowFooter = !(state.isChat && !state.bannerDetail?.shareSidebar) && state.bannerImageInfo?.id = !(false && false) && 44 = true,应该显示底部分享按钮才对,可是为什么不显示呢。这是一个令人感到困惑的地方,一时间破案陷入僵局。没有了思路。
打破僵局有一句说的好,只要思想不滑坡,方法总比问题多。在网上不断搜索调试方法,不断尝试,功夫不负有心人,终于找到了救星。这个救星就是Chrome浏览器自带的文件替换功能。下面我们来看看如何使用这个神器,破解僵局。
第一步 查找调试文件如何找到要调试的在线业务文件呢?从Chrome开发调试工具的网络面板中可以看到,这个页面大约有20多个脚本文件请求,而大部分根据名称就能排除掉。比如像sdkMsgXXX.js,polyfillXXX.js,vue.XXX.js,vant.XXX,js 等。真正需要查看文件内容的,也就是其中3个以index.XXX.js命名的文件。然后依次点击这三个index.XXX.js文件, 按下CTRL+F搜索快捷键,输入上下文关联变量isChat,定位出要调试的业务文件是index.58a9f303.js。
image.png第二步 启用文件替换功能在本地创建一个文件夹,名称随意。这里命名为assets。然后切换到Chrome开发调试工具的源代码面板,点击下方的替换==选择放置替换项的文件夹==选择刚才创建的assets文件夹,接着浏览器会弹出一行文字,询问是否给予浏览器完整访问本地文件夹的权限,选择允许。
image.png接着点击启用本地文件
image.png切换到浏览器开发调试工具的网络面板,找到刚才定位到的文件,鼠标右键,点击保存并覆盖。之后刷新页面,浏览器每次就会读取本地的文件而不是线上的文件,改本地文件调试代码是令程序员感到很舒服的事情。这个功能极大了方便了调试在线问题。
image.png第三步 修改代码调试上一步保存到本地的在线文件,是个混淆压缩文件, 可读性比较差。我们可以在VSCode中打开这个文件,对这个代码进行美化,然后添加调试打印语句
image.png刷新页面,可以看到,空值台输出了isShowFooter相关的三个响应式变量的取值。
image.png令人诧异的是,这条日志应该打印两次,而实际上只执行了一次。从打印出来的值来看,就是页面初始化的时候执行了一次,后面接口数据返回后,被没有再次执行,这是为什么呢?
第四步 破案我思考了良久,综合查看的页面的dom结构,接口数据,打印日志,认为最有可能出错的地方,就是isShowFooter计算表达式那里。
constisShowFooter=computed(()={
return!(state.isChat!state.bannerDetail?.shareSidebar)state.bannerImageInfo?.id;
});
查看了一下压缩文件,结合源代码推算出混淆压缩文件中的st代表vue的computed关键字, 分别查看一下逻辑正确的测试环境和有问题的生产环境,这个st是怎么来的。
测试环境,st是从./vue.183497e1.js中导出来的。
import{
uasY,
wasU,
_as$,
CasM,
basH,
oaskt,
HasAt,
yas$t
}from"./index.be88cf51.js";
import{
jasT,
Saslt,
JasTt,
Kass,
Pasm,
Qaso,
uast,
_asD,
Lasb,
MasC,
tasB,
aasO,
basdt,
kasf,
a0asW,
a1asX,
HasG,
Oasg,
$asz,
rasN,
Yasxt,
FasSt,
UasLt,
Vasst,
}from"./vue.183497e1.js";
生产环境,st是从index.c3315d0c.js导出的。
import{
uasX,
wasU,
_as$,
CasM,
basH,
oaskt,
aRasst,
HasAt,
yas$t
}from"./index.c3315d0c.js";
import{
jasT,
Saslt,
JasTt,
Kass,
Pasm,
Qaso,
uast,
ZasD,
Lasb,
MasC,
tasB,
aasO,
basdt,
kasf,
$asW,
a0asY,
HasG,
Oasg,
_asz,
rasN,
Xasxt,
FasSt,
UasLt,
}from"./vue.85dd2d76.js";
是不是这个st导出文件不同,引起的生产问题?验证一下。将生产环境中的st导出方式,修改为和测试环境一样,从./vue.85dd2d76.js导出st。
import{
//...
Vasst
}from"./vue.85dd2d76.js";
将从./index.c3315d0c.js导出的st变量删除
import{
//...
//删除这句
aRasst,
}from"./index.c3315d0c.js";
保存文件,Ctrl+R刷新页面,可以看到,isShowFooter的运行逻辑正常了,分享按钮也显示出来了。至此,本案告破。
image.png最后Chrome开发工具还有这么好用的功能,以前也看到过,泛泛而学。等真的遇到问题需要使用的时候,根本想不起来。所以我感觉,学习知识要带着应用场景去学,你怎么用,就怎么记忆,学习要学到可以应用的程度。否则可能会产生虚假的收获感和充实感,以为自己把时间都用在了该用的地方,当时也感觉学到了不少知识。然而实践是检验真理的唯一标准,等需要用的时候,如果联想不起来,学过就等于白学。实践不会陪你演戏。
如果文章对你有帮助的话欢迎「关注+点赞+收藏」
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线