记一次require+闭包的bug检查
来源:互联网 发布:英语四级真题推荐知乎 编辑:程序博客网 时间:2024/05/01 11:21
今天的你,写bug了吗?
唉什么都不想说,只怪自己太蠢。闭包和引用,两个最基础的知识,结合到了一起,却忘得一干二净,谨以此文,来记录下这个已经被我K.O的bug,愿来生路上,你不再出现。
情况是这样的,有个函数一个网络请求加处理步骤,结构大概是这样
let result = {}function func(url) { return new Promise((resolve, reject) => { request(url, (err, res, body) => { // 处理result并resolve出去 }) })}module.exports = func
本来觉得写一起好了,然后发现越写越长,于是就把它放到了另一个文件里面,然后主函数来引用。
不自觉为自己点个赞
于是乎,大刀阔斧地把这个函数给分离了出去,主函数的结构是这样
const func = require('./func')let arr = []let result = await func(url)arr.push(unit)
最后来讲arr转换成字符串写入文件,结果这个时候就出现一个问题了,什么问题呢,写完发现文件里面的所有result都是最后一次返回的result,bug就此出现。
what happened?
其实聪明的你估计早就已经发现问题在哪儿了,但当是写了一天代码的我,头昏脑胀,完全不知道问题出在哪儿,定位了一圈,发现全出在这个引用的函数里面,然后我便去函数里面找bug,最后终于发现了问题,就出现代码开头的第一句里面,就是下面这句
let result = {}
这句定义了一个对象,然后经由func函数处理并返回,但问题就在这是个对象上面,下面一步一步来解释
result对象定义在func函数的外部,而模块exports出去的是这个函数,这样在主文件里面引用的时候,result共享的都是一个实例,这就是require的特性,也就是说,即使在主文件里面多次调用func函数,这样只要result函数在func函数内部没有改变指向,那么arr里面每次接收到的result都是一个实例,所以也就出现了虽然多次push都是不同的,但是在result改变时,arr里面的所有元素都会跟result同步改变。
其实一个很简单的例子就能体现出这个结果
let a = []let b = {prop: 123}for(let i=0;i<3;i++){ b.prop++ a.push(b)}
这样最后你会发现a的内部所有的元素都会变为{prop: 126}.
回到上面的问题,主函数require进来的func其实相当于一个闭包,而这个闭包引用了result,而且由于require共享一个实例,这样每次改变result,自然arr的元素就会跟着改变了。
解决问题容易,但是如何避免问题,才是我们应该关注的问题。
这还只是个两个文件的程序,一个大型的应用程序可能几百个文件都很正常,这样如果某一个变量定义不慎,出现上面的问题,那么bug定位就比这个要难多了。
好了,今天的bug说就到这里,下期节目再见。
写bug去了
- 记一次require+闭包的bug检查
- 记一次CEdit的bug
- 记一次神秘的BUG
- 记一次愚蠢的BUG
- 记一次不愉快的bug修复
- 记一次CSS弹出动画的Bug
- 记一次有趣的bug查找
- 记一次CSS引发的小Bug
- 趣图:记一次百思不得其解的 Bug/异常
- 记一次百思不得其解的 Bug/异常
- 记一次关于list的bug
- 记一次 BUG 的排查过程
- require.js的一次简单尝试
- 记一次bug追踪
- 内存bug的检查列表
- 一次难忘的Bug经历
- Flash,一次Bug的思考
- 一次memcpy引起的bug
- 2638: 黑白染色
- 正则表达式Regex
- windows下cmd命令行,path搜索路径
- vi编辑器常用命令大全
- python基础入门(4)
- 记一次require+闭包的bug检查
- 感知器算法——C++实现
- Android中拍照和录像功能
- maven常用cmd命令
- ASP.NET MVC 分部页 PartialViewResult
- cocos2d-x-lua:API-瞬时动作
- efm32 c语言1
- Hadoop+hbase+zookeeper整合
- javascript concat(),slice(),splice()方法