被逮到一个初始状态考虑不周的Bug

简介:
这两天是产品beta1以后进行的新一轮bug扫荡,beta1以前产品的bug降低到了大家非常满意的水平。但是beta1以后QA Team发飚,bug总数biu的一下又上升到人均20个上下,真是让人恼火。不过幸好大部分是为了发布beta1而回归出来的UI方面的bug,不过今天却发现被逮到一个非常隐蔽的控件初始状态考虑不足的bug

    这个bug发生在一个纯脚本的TreeView控件上面,其异常表现为: 当使用键盘Up&Down键移动TreeView上面被选中的Item时,IE报告currentNode为空的脚本错误。关于这个功能的详细设计,可以参看本文,示例效果为:
   
    上图中的node就是程序中的currentNode,Up&Down操作就是根据这个node来进行计算并移动的。在TreeView控件中,为了处理TreeView节点被多选时找到一个确切的currentNode,在每次选择操作时,我在TreeView实例的全局cache中纪录了一个叫m_LastSelected的值,保存最后一次选择动作中的第一个节点。如果是单选就是被选中的节点本身,如果是多选,就是多选时第一个被选中的节点。

Tree.__ContainerOnKeyDown =  function()
{
     //  . . .
     if ( innerCache.m_Selecteds.m_Count == 0 )
    {
         return;
    }
     var currentNode = innerCache.m_LastSelected;
     //  . . .
}

    Review上面这段代码,取currentNode的地方似乎是已经做了安全检查,可是怎么还是出错了呢?其实除了本身程序有错,上面这个校验代码也是不对的,我检查的是m_Selecteds这个集合里面有没有东西,然后却是用m_LastSelected赋的值,这之间就可能出现m_Selecteds和m_LastSelected不同步的问题。结果确实是m_Selecteds和m_LastSelected之间的关联出了问题!看下面的代码:
TreeNode.__ContentOnMouseDown =  function()
{
     //  . . .
     if ( (!evt.shiftKey && !evt.ctrlKey) || !objNode.Attributes('IsMultipleSelected') )
    {
        innerCache.UnselectAll();
        objNode.SetSelected( true);
        innerCache.m_LastSelected = objNode;
    }
     //  . . .    
};
    由于m_LastSelected和node的选取顺序有关系,它被实现在了鼠标选择TreeView节点的逻辑中,即每次节点被鼠标点选就会更新m_LastSelected的值。

    这个逻辑似乎是没有什么问题,反正只要是选择了TreeView上的节点,就会有m_LastSelected的存在,我们也就会得到Up&Down操作的计步节点currentNode。可是就是这里漏掉了一个情况的考虑,如果被选中节点是在initialize我们的TreeView时,由调用代码来设置给节点的(示例如下)。那么由于实现时的疏忽,就出现了m_Selecteds非空,而m_LastSelected为空的情况。
var tree =  new Tree();
var node = TreeNode(' default node');
tree.Add(node);
tree.Show(/* treeview container element*/);
node.SetSelected( true);

    SetSelected(isSelected)方法实现如下:
TreeNode.prototype.SetSelected =  function(isSelected)
{
     var innerCache =  this.m_Tree.m_InnerCache;
     if ( isSelected )
    {
         if ( !innerCache.m_Selecteds.Contains( this) ) 
        {
            innerCache.m_Selecteds.Add( this);
        }
    }
     else
    {
        innerCache.m_Selecteds.Remove( this);
    }
     if (  this.m_Selected != isSelected )
    {
         this.m_Selected = isSelected;
         if (  this.e_SelectedChanged )
        {
             this.e_SelectedChanged.Execute(isSelected);
        }
    }
     this.ApplyUIChange();
};
    问题就是这里了,调用SetSelected选中了节点后,m_Selecteds这个集合是更新了,可是却没有设置m_LastSelected(由于Last Selected Node的定义,本身是不该在这里设置),这样就造成了m_Selecteds和m_LastSelected的不同步。从而出现了开始说到的,进行Up&Down操作结果出现currentNode为空的错误。

    这个bug如果是Review代码可能细心能找出来,可是直接被QA通过黑合测试给提了出来,确实是相当相当不容易的。因为刚初始化好的TreeView是没有获得焦点的,这时不管怎么按Up&Down键都不会有反映,也就看起来并没有什么错误。如果使用鼠标点击一下TreeView内的任何区域,让其获得焦点,那么至少都会选中一个TreeNode,这样一来m_LastSelected也就有值了。那么这个如此隐蔽的bug是怎么发现的呢?这需要在页面载入并在TreeView生成后,立即使用Tab键把焦点移到TreeView的container元素上,这时候按Up&Down键,如果TreeView上面有初始花时被SetSelected(isSelected)选中的节点,那么就出错了


本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。

目录
相关文章
|
6月前
bug长时间未修复该怎么办?
bug长时间未修复该怎么办?
bug长时间未修复该怎么办?
|
6月前
|
算法 前端开发
3029. 将单词恢复初始状态所需的最短时间 I
3029. 将单词恢复初始状态所需的最短时间 I
30 0
|
6月前
|
前端开发
修正一些formdesigner的一些bug与操作
修正一些formdesigner的一些bug与操作
49 1
|
6月前
|
数据可视化 定位技术
学无止境——记录一个被别人发现的bug
学无止境——记录一个被别人发现的bug
学无止境——记录一个被别人发现的bug
|
SQL 关系型数据库 数据库
记一次程序 Bug 导致数据删除的恢复过程
使用RDS、DMS进行数据恢复实践
999 0
好家伙!查看系统日志时我捕获了一只发生概率小于万分之一的Bug
在开始这篇文章之前想先说一句:如果一套系统暂时没问题,那只是因为它的并发量不够而已。 上周在查看系统日志时,发现了一条与众不同的日志。日志中有一半内容是正常的报文数据,而另一半内容是0x00这样的空数据
|
IDE 开发工具
STM32bug【 KEILMDK中出现STLink强制更新提示,又无法更新】
STM32bug【 KEILMDK中出现STLink强制更新提示,又无法更新】
381 0
|
设计模式 算法 Java
干掉 “重复代码” 的技巧有哪些
软件工程师和码农最大的区别就是平时写代码时习惯问题,码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。
133 0
干掉 “重复代码” 的技巧有哪些
|
Web App开发 JavaScript 前端开发
前端BUG录- audio 意外的 Pending 挂起状态
最近公司一直在做众审平台相关的功能,大多数还都和音视频有关,前端终究还是逃不过这一劫。 疯狂遇到 BUG, 今天来说说其中一个:audio 加载时意外的长时间 Pending 问题。
327 0
|
缓存 索引
代码没有任何改动,为什么程序执行会有Bug?
题记:工作中经常遇到开发不同的版本,如版本5.1、版本5.2,5.2版本是在5.1版本上的升级,会修改已有几个模块的功能或者新增功能。但对于其中一个模块M,没有做任何修改,奇怪的是,为什么5.2版本的模块M会有Bug?
169 0