分享bug的目的
开发过程中bug常相伴, 不能修复或者无法复现就忽略这些问题, 所以计划每当我遇到9个有价值有思考的bug就会统一分享出来, 以此来扩展性的思考工作本身, 不断的提高自己的意识, 毕竟能力的提高遇到的bug一定不同, 而且如果遇到bug越来越少只能说明自己的工作任务与学习任务在'原地踏步,且不饱和', 既然如此就靠bug来见证自己的成长吧.
1: element-ui: el-card标签
bug现象:
有一天测试突然跟我说, 一个当前版本根本没动过的页面发生bug, 页面有些数据为空, 有些按钮点击无效.
bug追查:
第一分析: 那好吧根本没动过的页面出问题那就是历史遗留问题或者后端返回出了问题, 那就去排查一番吧,但是排查的过程令我傻眼, 后台返回了值但是莫名其妙的一直在报'空值'的错, 而且这是一个三年的老项目还是其他项目组转过来了, 说实话代码很烂很乱, 使用了大量的mixin还有部分逻辑进入了node_modules里面还没有文档, 这个时候只能暴力破解了, 打个debugger一步一步的追查下去, 真的定位了很久发现了关键点, 是某个子组件没有得到传值, 然后这个子组件还会往父组件传一个值, 这才导致了父组件里面的某些值为空从而报错, 看了看向线上的项目没有这些问题, 这有我这个版本有问题那么一定是有人动了这一页的代码, 或者整体环境的某个全局属性被篡改了那问题涉及就广了, 调出gitlab当前页的上一个版本代码,(这里是一个小技巧)把当前代码commit, 生成缓存然后把上个版本的代码覆盖当前代码, 在deff里面就可以看到两版本代码的差异了, 我发现原本根标签是<div>...</div>, 而这次的是<el-card></el-card>, 思维有点堵塞:就换了个标签而已, 不涉及任何的属性与变量, 怎么可能导致数据崩溃??
bug原因:
罪魁祸首是这个this.$parent
, 原来上一个同学在组件里面是通过父级组件的实例来获取父级传过来的数据的, 那么问题明了了<el-card></el-card>标签成为了他的父级, 那么它理所当然的取不到更上一级的数据了, 所以获取到的数据就是空的,'凶手'就是它.
bug解决:
- 改
this.$parent
为'行间传值'的形式, 并测试是否好用. - 寻找全局是否还有类似的情况, 一一改正.
- 找到添加<el-card>的同学, 说明原因, 以及询问他是否还如此改变过其他地方的代码, 放弃其他工程也出现类型的情况.
bug思考:this.$parent
或者是 this.$children
这种方式获取与传递数据十分不妥, 因为没有明确数据来源与使用者, 这样就会导致除了问题很难排查, 这种"父与子"的关系很脆弱,很容易突然'父组件'变成爷爷组件了, bug也就随之而来, 所以不是不得已的情况下或是高度封装的环境下, 不推荐使用.
随意的改变一块代码, 你的知识范围里面感觉没有影响,但不代表就真的没有影响, 不要忽视"验证"这个环节, 自己写的代码自己需要负责任ok?
2: antv: 折线图倒叙
bug现象:
之前使用公司二次封装的echarts开发, 这个版本使用了antv来开发图表, 但是怪异的事情出现了, 折线图的'y轴'出现了倒叙的现象, 也就是 10, 5, 0 这种怪异的排列, 导致图表上下颠倒.
bug追查:
之前没有类似问题, 这个版本才出现, 这个版本后端没有动接口, 那么问题就在这个组件的使用上, 第一分析: 是否有这样一个属性, 控制了y轴的正反? 去看文档没有找到, 第二分析: 去看官网的实例, 一个字母都不差的拷贝过来但还是反的, 第三分析: 那么问题出在数据上, 但是数据没有变换, 那么问题出在两套插件处理数据的机制上, 仔细观察再仔细观察, 发现了!原来后台返回的数字是'字符串类型的'.
bug原因:
原来antv只会对'number'进行从小到大的排序, 汉字的话就按接收顺序显示了, 我把组数据都+一下就ok了
bug思考:
不同组件库对数据的处理形式也是不同的, 不要以为换了个组件库知识变动api的方法就可以了, 还会有很多'原罪'.
通过使用三套不同的图表库, 使我受益匪浅, 并不是图表绚丽的效果, 而是对每种图表调用方式的思考, 让我更深入的理解设计模式.
3: 正则: 前瞻性匹配vs火狐
bug现象:
项目突然无法在火狐,ie浏览器上运行,当然项目只需要在谷歌浏览器运行, 但是这个现象我还是想探究一下.
bug追查:
本次排查顺序不太对, 我先看上个版本是否都可以在火狐运行, 发现上个版本没问题那就把问题定位在当前版本, 其实应该先看控制台报错, 但是由于页面是空白的理所当然的认为完全崩溃了, 或者是后台返回错了, (下次一定先追查控制台的报错信息) 也就是这一段"SyntaxError: invalid regexp group", 是前瞻性匹配出了问题, 我在为数值加千分号的过滤器上使用了如下的代码, (其实我自己写的是翻转字符串逢3位加',')
export default {
install(vm) { // 如果后面是3的倍数,那么就加一个','
vm.filter('formatThousand', (num) => {
if (!num) return 0;
const reg = /\d{1,3}(?=(\d{3})+$)/g;
return (`${num}`).replace(reg, '$&,');
});
},
};
那么注释掉这个代码就不报错了么?答案是否定的, 报错仍然在继续, 我打开vscode的搜索台, 输入了前瞻性匹配的语法, 但是啥也搜不到, 思考....vscode搜索台也是有局限的, 比如他不会深入到node_modules里面查找, 这样也是为了性能, 那么一定是这次新引入的插件除了问题, 经过查找果然是因为我们自己公司制作的'3d视图'组件使用了正则的前瞻匹配, 但是为了更好的推进公司技术的发展还必须使用公司的技术, 那么现在不是抱怨而是反馈, 把这个问题与可视化部门明确, 还好当前项目本就不用刻意兼容火狐但是其他项目要注意喽.
啥是前瞻性匹配:
正则是js基础, 如果不熟练的同学需要反省了,?还可以解除贪婪模式
(?=exp)匹配后面满足表达式exp的位置
(?!exp)匹配后面不满足表达式exp的位置
bug原因:
原来ie与火狐浏览器并不支持前瞻性匹配
bug思考:
很多时候我们会忽略某些方法的兼容性, 甚至某些插件没有照顾兼容性, 那么选技术的时候一定要根据项目要求而定. 若是我们自己开发插件也要写好兼容范围方便大家使用.
4: scss: 引入scss文件无效
bug现象:
需要全局改变table相关的样式, 我单独抽出了个scss文件放在最外层, 但是怪异的事情发生了, scss文件里面的嵌套写法不生效, 必须要拿出来像css文件一样的写法才生效
bug追查:
定位问题:嵌套的写法无效, 那么变量是否有效?答案是也无效, 那就是说我引入了scss文件没问题, 系统也解析, 但是scss的写法系统不认识, 那么难道是我的scss-loader坏了?? 每个vue文件里面写上lang='scss'都是没问题的, 那么找之前的工程的引入方式复制粘贴,还是不行....
bug原因:
css的引入两种方式, 有一种是scss提供的如下:
使用第二种方式可以正确的解析scss文件
@import url('./assets/style/animation.css'); // css提供的
@import '@/assets/style/animation.scss'; // scss提供的
bug思考:
不要小瞧引入方式.
编写项目css是非常重要的一部分, 主要有'ben'与'oocss'两种思想,有的人直接把css写在html文件里面, 也有人直接写在 app.vue文件里面不加'scoped
'就是全局的模式了, 这些当然都没问题,但是毕竟我们是有追求的工程师, 要做到'美观'与'工程化', '色香味俱全'才是好的代码.
5: vue: 文件夹不要叫bin
bug现象:
我上一篇文章里面分享了如何在项目里面做mock的工程化, 但是吧mock工程放入某些工程之后出现了怪异的错误, 首先可以正常启动, 8080端口也启动成功, 但是...浏览器访问的一瞬间就会终止localhost的服务, 强制退出可还行??
bug追查:
说实话第一时间脑海空白, 具体的原因想不通, 反复试验了几次之后确定了bug的具体现象, 在每个操作处打debugger, 仍然追查不到原因, 但是报错都是在bin这个文件夹里面, 里面的文件也都没问题正常的执行, 那么会不会是这个bin文件夹本身有问题, 改个名字试试? 还真就好了~~
bug原因:
bin这个文件名比较特殊, 改成其他的立刻就好了
bug思考:
不要轻易使用系统常用文件名, 之前有一次写我自己的ccpack也是js的index文件与node环境的index文件冲突, 不可以都叫index...., 起名也要谨慎啊.
6: token: 储存在哪里比较好?
bug现象:
我们的token一直都是存在cookie里面, 可是最近在深入学习web安全相关知识, 感觉这样并不一定对.
bug原因:
csrf攻击如下: 你在a网站登录成功, b是钓鱼网站, 你点击b的时候会向a网站发送请求冒充你本人的请求, 这个时候浏览器会默认带上你在a网站登录的cookie信息发送过去, 而这个请求不光利用img标签进行get请求, 还可以利用form表单进行post请求, 所以这个token不能放在cookie这种位置吧, 而且还不是httponly, 更合理的是放在local storage里面, 每次请求附加在header上面, 并且随时准备更新它,这样csrf的时候是取不到local storage的值的.
bug问题反馈:
与相关同学交流了这个问题, 因为在cookie加上token是后端直接操作的, 但是由于这个问题后端同学已经封装在统一的中间件里面, 要是修改的话涉及面有一些广, 但是其他的方式可以起到补救的效果, 比如验证referer 来源信息, 白名单, 二次验证等等.
在这个问题上得到的启示是, 很多核心的逻辑不可以草草就制定, 而且能做到更好为什么不做那?
7: pm2: restart并不靠谱
bug起因:
现在服务端渲染的项目也不少, 前端工程师大部分都是使用node来做的, 线程保护方面大部分也是选用pm2, 毕竟pm2简洁明了还自带'负载均衡'
bug现象:
在本地与test环境都没问题, 上线的晚上我执行了以下操作
sudo -s
cd /home/xxxx/xxxx/ // 线上环境目录
git pull
npm run build
pm2 restart all
但是奇怪的事情发生了, 启动的时候都是'成功', 过了2秒钟, 其中四个server变成了error, (为什么是4个server, 因为分配了四核)我重新build项目, 再次pm2 restart all
仍然无效, bug来了开始本该兴奋, 但是奈何正在上线项目大家都很急,那就需要紧张起来了, 先看onerror日志因为在服务器环境所以只能cat看, 但是日志一团乱麻看了一会没有找到真正的原因, 难道是build出了大问题?test是好的啊, 当时陷入了反复build与restart的傻操作, 冷静一下和这个问题有没有可能不是打包错误而是服务错误? 问题不在我们的代码而是在pm2本身出现了冲突之类的, 那好假设'restart重启'不能解决问题, 那我直接 pm2 delete id 这样删除掉4个server, 然后 pm2 start ./server.js -i 4
重新启动还真就ok了.
bug分析:
遇到事情从自己身上找原因是好的品质, 但是不可以只局限在怀疑自己, 也要考虑也许是其他技术出了问题.
pm2也只是个系统, 偶尔不是重启他监控的项目而是重启它本身.
8: vue: $变量的用处
bug起因:
公司的3d技术团队开发的一套组件, 在接收实例的时候命名必须是'$a'不可以是'a'.
请教了可视化团队的同学, 得知$与_开头的变量不会被vue监控, 这样这个变量我们可以自己来监控, 更加的灵活.
使用$:
在data里面定义$txt变量并且在行间<span>{{$txt}}</span>报错如下:
`Property "$txt" must be accessed with "$data.$txt" because properties starting with "$" or "_" are not proxied in the Vue instance to prevent conflicts with Vue internals.`
必须使用“$data.$txt”访问属性'$txt',因为在Vue实例中不代理以 "$" or "_"开头的属性,以防止与Vue内部发生冲突。
使用_:
在data里面定义_txt变量并且在行间<span>{{_txt}}</span>报错如下:
`Keys starting with with '_' are reserved`
以'_'开头的键被保留
学习'bug':
data(){
return {
$txt:{},
}
},
created(){
this.$txt = {n:2};
},
mounted(){
console.log(this.$txt) // {n:2} 但是, span标签里面的值不会变
}
我们来对他进行监控
created() {
this.$txt = { n: 2 };
let n = 2;
Object.defineProperty(this.$txt, "n", {
get() {
return n;
},
set(val) {
return (n = val);
}
});
},
mounted() {
this.$txt.n = 3;
console.log(this.$txt.n); // 3
}
这样就实现了: 数据挂在data上面可以取到, 但是这个数据又没有vue进行监控, 这样玩法就多了去了, 是个挺不错的思维.
解释
因为我用'a'接值会导致vue的观察与3d团队的观察冲突, 所以报错'$a'当然就不冲突了
反馈
这个技术点我已于3d团队进行反馈, 希望在文档中明确, 防止其他同学挠头.
9: dom: ResizeObserver
bug显现:
在使用可视化团队开发的图标组件时发现了问题, 当窗口size变化的时候, 图标会自动调整自己的布局宽度, 但是...这个图标是100%充满父级的, 或者是flex:1充满父级的, 当他的父级变化,并没有出发winodw.onresize的事件的时候, 突变没有调整自己的宽度.
bug起因:
只监控了窗口的尺寸变化, 忽略了父级本身的尺寸变化
bug解决方案1:
我对可以使其父级宽度变化的function加上了一个cb, 这样就知道父级的每次更改了, 但是这个需要在能影响父级变化的函数里面逐一的加.
bug解决方案2: 限谷歌
神奇的ResizeObserver, 简直好用
<template>
<div>
<div ref="wrap" class="wrap">
<div class="box">1</div>
</div>
</div>
</template>
<script>
export default {
mounted(){
const wrap = this.$refs.wrap;
// 创建监控实例
const resizeObserver = new ResizeObserver((item)=>{
console.log('变化', item) // item是数组, 变化者们
});
// 投入被观察者dom
resizeObserver.observe(wrap)
// 当然可以解除观察, 性能不用太担心
// resizeObserver.unobserve(wrap);
}
}
</script>
<style>
.wrap{
border: 1px solid red;
width: 50%;
}
.box{
border: 1px solid black;
margin: 20px;
}
</style>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。