被逮到一个初始状态考虑不周的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;
}
varcurrentNode=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为空的情况。
vartree=newTree();
varnode=TreeNode('defaultnode');
tree.Add(node);
tree.Show(/* treeview container element*/);
node.SetSelected(
true);

SetSelected(isSelected)方法实现如下:
TreeNode.prototype.SetSelected=function(isSelected)
{
varinnerCache=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)选中的节点,那么就出错了

优质内容筛选与推荐>>
1、居中
2、odoo 附件上传与下载
3、强势的fetch
4、a configuration error occured during startup.please verify the preference field with the prompt:cannot connect to VMtomcat debug错误时
5、Git常用命令解说


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号