现在有一个需求:
如果“一个字符串”超出“容器宽度”,将字符串截断最后一个字符、并在末尾加上‘...’ ,再次判断是否需要截断。直至字符串小于容器宽度。
下面SliceLabelStr函数采用了递归:
如果文字超出宽度,在attrStyle函数中将原字符截断末尾字符并加上‘...’ 再次调用sliceLabelStr判断是否超出宽度。
直至获得宽度合适的字符串并输出。
需要优化的递归函数
sliceLabelStr = function( textWidth, textStr) {
var str;
if(超出宽度) {
dataLabel2 = attrStyle(textStr);
var newTextWidth = dataLabel2.text && dataLabel2.text.element.getBoundingClientRect().width;
var textStr = dataLabel2.text.textStr;
sliceLabelStr( newTextWidth, textStr);
} else {
str = attrStyle(textStr, true);
return str;
}
}
这样看起来没问题。其实需要优化很多地方。
1、递归没有出口
这个递归函数被调用了10遍,在11遍的时候符合了出口条件退出了,
那么在第10遍没退出的时候,1到10次的函数都没有退出,只有在第11遍符合了出口条件return了以后,就会从11~1倒着依次退出
附上一张太阳神手写的解释图
优化方法1
if(textWidth > containerWidth) {
dataLabel2 = attrStyle(textStr);
var newTextWidth = dataLabel2.text && dataLabel2.text.element.getBoundingClientRect().width;
var textStr = dataLabel2.text.textStr;
return sliceLabelStr( newTextWidth, textStr);//有返回值
}
1、上述原因是递归没有出口,而且if语句中调用本函数递归的时候没有返回值。
2、有时会产生“调用栈溢出”的情况。
2、在if判断条件中,由于在某种情况下textWidth没有变化造成了无限递归
3、用do...while 代替 递归
sliceLabelStr = function(forX2Array, textWidth, textStr) {
var str,
sliceStr = textStr.text && textStr.text.textStr || textStr;
if(compareTextLength(forX2Array, textWidth)) {
var n=0;
do{
n++;
}
while(sliceStr.substr(0,n)!=sliceStr && attrLabel2Style(forX2Array[0], sliceStr.substr(0,n)).getBBox()["width"]<ContainerWidth(forX2Array))
return sliceStr.substr(0,n);
} else {
str = attrLabel2Style(forX2Array[0], sliceStr, true);
return str;
}
}
逻辑比较直观,简单能用循环的就用循环,递归一般用在复杂算法,比如弗洛伊德,A+之类
4、这是SVGElement,如果是普通的DOM元素。可以用如下方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。