前段时间开始做一个thinkjs的项目,thinkjs本身相当简洁好用,直到遇到这个神奇的bug
某一天,我在享受着用webstorm写代码的快感,感觉马上就要突破新境界的时候,Ctrl+S保存一下,然后这个代码文件突然就不见了,被删了,IDE的代码窗口也自动关闭。。。然后脑子一呆:我刚才干什么了,我刚才删文件了吗?回收站还有吗,没有!我好像没删文件啊?莫非磁盘挂了?
作为团队的技术担当,我是不会跟人说我代码写着写着突然就丢了,没人会相信代码文件会自己删除,大家一定是认为我手抖自己删了,这太没面子了。。
没办法,只能默默的含着泪把代码再写一遍,感觉自己的智商收到了侮辱,暗暗发誓一定要找出到底是什么原因弄丢了代码。
第一个怀疑的是磁盘挂了,查系统日志没任何问题;再怀疑是不是我自己的thinkjs里关于清理老图片文件代码删错文件了,查了N遍代码,也没问题;甚至怀疑是不是我写的某个代码片段跟那个木马病毒的脚本特征匹配上被杀软删了,可我压根没装杀软啊。。连自己都一度怀疑是自己手抖删掉了。。。直到过了两天,同事也遇到了代码被删的问题,也是代码在调试的时候。。
然后我才把目标转向thinkjs的代码变化自动重新加载功能,然后去翻think-watch的代码,发现了下面这段代码:
const srcFiles = helper.getdirFiles(srcPath).filter(file => {
return options.filter({path: srcPath, file}, options);
});
let diffFiles = [];
if (diffPath) {
diffFiles = helper.getdirFiles(diffPath).filter(file => {
return options.filter({path: diffPath, file}, options);
});
this.removeDeletedFiles(srcFiles, diffFiles, diffPath);
}
removeDeletedFiles的功能是如果有个文件在diffFiles数组中,而不在srcFiles数组中,就删除这个文件。
问题就出在这段代码,调试发现大部分情况下srcPath和diffPath是同一个路径,也就是对一个路径枚举两遍,如果第二次枚举多了什么文件,就把这个文件删掉。。。可以想象,如果第一次枚举完的时候正好一个文件修改保存了,那第二次枚举的时候就会枚举到这个文件,然后就会把这个文件删除,为了验证,我写了个脚本频繁修改一个文件,然后过段时间发现文件就被删了。。。
修正后的代码
assert(path.isAbsolute(srcPath), 'srcPath must be an absolute path');
const diffPath = options.diffPath[index];
let diffFiles = [];
if (diffPath) {
diffFiles = helper.getdirFiles(diffPath).filter(file => {
return options.filter({path: diffPath, file}, options);
});
}
const srcFiles = helper.getdirFiles(srcPath).filter(file => {
return options.filter({path: srcPath, file}, options);
});
if (diffPath) {
this.removeDeletedFiles(srcFiles, diffFiles, diffPath);
}