先看原始代码
其实这是一个老项目,本可以只解决 Bug 即可,不需要做其他的工作。但是没有办法,强迫症比较严重,哈哈!代码是这样的:
$scope.proInfoChange = function( info ) {
if (($scope.newInfo.Width >=screenWidth )||($scope.newInfo.Height >=screenHeight )) {
var scaleX = screenWidth / $scope.newInfo.Width;
var scaleY = screenHeight / $scope.newInfo.Height;
var scale;
if (scaleX < scaleY) {
scale = scaleX;
info.Width = parseInt(screenWidth/scale);
info.Height = parseInt($scope.newInfo.Height)
}else{
scale = scaleY;
info.Width = parseInt($scope.newInfo.Width);
info.Height = parseInt(screenHeight/scale);
}
info.Scale = parseFloat(scale.toFixed(2));
$scope.newInfo.Scale=info.Scale;
// $scope.maxScale = info.Scale;
// sessionStorage.setItem("maxScale",JSON.stringify($scope.maxScale))
// sessionStorage.setItem("displayInfo",JSON.stringify($scope.newInfo))
}else if ($scope.newInfo.Width &&$scope.newInfo.Height &&$scope.newInfo.Width < screenWidth &&$scope.newInfo.Height < screenHeight ) {
info.Width = $scope.newInfo.Width;
info.Height = $scope.newInfo.Height;
$scope.newInfo.Scale=info.Scale = 1;
}else{
return false
}
preview.setWinfoBase(info);
var value = JSON.stringify(info);
sessionStorage.setItem("windowInfo",value);
dataChange();
};
看得懂吗?是不是一脸懵逼?
这段代码的作用是这样的,页面有一个容器,当改变容器的大小时,将其大小与视口大小对比,将其进行缩放,避免超过视口大小。当然,这个方法不是本人写的,本人也是仔细看了上下文才知道的。下面我们就开始优化吧!
开始优化
第一步:删除过期注释
将注释掉的代码全部删除,想找回的时候用 Git 。Git 可是基本操作,必须得会的。于是代码变成了下面这样:
$scope.proInfoChange = function( info ) {
if (($scope.newInfo.Width >=screenWidth )||($scope.newInfo.Height >=screenHeight )) {
var scaleX = screenWidth / $scope.newInfo.Width;
var scaleY = screenHeight / $scope.newInfo.Height;
var scale;
if (scaleX < scaleY) {
scale = scaleX;
info.Width = parseInt(screenWidth/scale);
info.Height = parseInt($scope.newInfo.Height)
}else{
scale = scaleY;
info.Width = parseInt($scope.newInfo.Width);
info.Height = parseInt(screenHeight/scale);
}
info.Scale = parseFloat(scale.toFixed(2));
$scope.newInfo.Scale=info.Scale;
}else if ($scope.newInfo.Width &&$scope.newInfo.Height &&$scope.newInfo.Width < screenWidth &&$scope.newInfo.Height < screenHeight ) {
info.Width = $scope.newInfo.Width;
info.Height = $scope.newInfo.Height;
$scope.newInfo.Scale=info.Scale = 1;
}else{
return false
}
preview.setWinfoBase(info);
var value = JSON.stringify(info);
sessionStorage.setItem("windowInfo",value);
dataChange();
};
第二步:合并变量声明
代码里有 4 个 var ,也就相当于有 4 句声明语句,语法解释器的脑子要转四下,太费劲了。我们可以把它们 合并为一句。于是代码变成了这样:
$scope.proInfoChange = function( info ) {
var scaleX = screenWidth / $scope.newInfo.Width,
scaleY = screenHeight / $scope.newInfo.Height,
scale,
value;
if (($scope.newInfo.Width >=screenWidth )||($scope.newInfo.Height >=screenHeight )) {
if (scaleX < scaleY) {
scale = scaleX;
info.Width = parseInt(screenWidth/scale);
info.Height = parseInt($scope.newInfo.Height)
}else{
scale = scaleY;
info.Width = parseInt($scope.newInfo.Width);
info.Height = parseInt(screenHeight/scale);
}
info.Scale = parseFloat(scale.toFixed(2));
$scope.newInfo.Scale=info.Scale;
}else if ($scope.newInfo.Width &&$scope.newInfo.Height &&$scope.newInfo.Width < screenWidth &&$scope.newInfo.Height < screenHeight ) {
info.Width = $scope.newInfo.Width;
info.Height = $scope.newInfo.Height;
$scope.newInfo.Scale=info.Scale = 1;
}else{
return false
}
preview.setWinfoBase(info);
value = JSON.stringify(info);
sessionStorage.setItem("windowInfo",value);
dataChange();
};
第三步:缓存多次出现的变量
通过搜索可以发现,$scope.newInfo.Width 和 $scope.newInfo.Height 各出现了 6 次,而且两个变量都处于一个多层嵌套的对象中,比较耗性能,我们可以将其缓存。代 码变成这样:
$scope.proInfoChange = function( info ) {
var newInfo = $scope.newInfo,
newW = newInfo.Width,
newH = newInfo.Height,
scaleX = screenWidth / newW,
scaleY = screenHeight / newH,
scale,
value;
if ((newW >=screenWidth )||(newH >=screenHeight )) {
if (scaleX < scaleY) {
scale = scaleX;
info.Width = parseInt(screenWidth/scale);
info.Height = parseInt(newH)
}else{
scale = scaleY;
info.Width = parseInt(newW);
info.Height = parseInt(screenHeight/scale);
}
info.Scale = parseFloat(scale.toFixed(2));
$scope.newInfo.Scale=info.Scale;
}else if (newW &&newH &&newW < screenWidth &&newH < screenHeight ) {
info.Width = newW;
info.Height = newH;
$scope.newInfo.Scale=info.Scale = 1;
}else{
return false
}
preview.setWinfoBase(info);
value = JSON.stringify(info);
sessionStorage.setItem("windowInfo",value);
dataChange();
};
第四步:代码逻辑优化
这个时候就比较考验耐性了,我们需要理清代码逻辑和具体的业务逻辑。业务逻辑是这 样的,用户可以输入容器的宽高来改变容器的大小,如果容器的大小超过了视口的大小 就对容器进行等比例缩放。其中,info 是需要保存的数据,其结构是这样的:
{
Width: 512,
Height: 256,
Scale: 1
}
而 newInfo 是 info 的一个拷贝(好吧,至于为什么要拷贝一个,我也不懂,不是很理 解同事的做法,哈哈,很尴尬 !),用于和页面中的输入框进行双向绑定,以便反馈用 户输入。
仔细观察可以发现,代码中出现了很多 if...else... ,而且
else {
return false
}
明显是可以去掉的。然后这一段
var newInfo = $scope.newInfo,
newW = newInfo.Width,
newH = newInfo.Height,
scaleX = screenWidth / newW,
scaleY = screenHeight / newH,
scale,
value;
if ((newW >=screenWidth )||(newH >=screenHeight )) {
...
}else if (newW &&newH &&newW < screenWidth &&newH < screenHeight ) {
...
}
是说,当容器的宽或者高超过视口时做什么什么,否则就怎么怎么样,else if 显然是多余的。所以 if...else if...else 可以进一步优化为:
if (newW && newH) {
if ((newW >=screenWidth) || (newH >= screenHeight)) {
...
} else {
...
}
}
然后代码就变成了这样:
$scope.proInfoChange = function( info ) {
var newInfo = $scope.newInfo,
newW = newInfo.Width,
newH = newInfo.Height,
scaleX = screenWidth / newW,
scaleY = screenHeight / newH,
scale,
value;
if (newW && newH) {
if ((newW >=screenWidth) || (newH >= screenHeight)) {
if (scaleX < scaleY) {
scale = scaleX;
info.Width = parseInt(screenWidth/scale);
info.Height = parseInt(newH)
}else{
scale = scaleY;
info.Width = parseInt(newW);
info.Height = parseInt(screenHeight/scale);
}
info.Scale = parseFloat(scale.toFixed(2));
$scope.newInfo.Scale=info.Scale;
} else {
info.Width = newW;
info.Height = newH;
$scope.newInfo.Scale=info.Scale = 1;
}
preview.setWinfoBase(info);
value = JSON.stringify(info);
sessionStorage.setItem("windowInfo",value);
dataChange();
}
};
第五步:修改错误的业务逻辑
其实这次改代码主要就是为了解决这个 Bug 。前面说过,newInfo 是用户输入,info 是要保存的数据,就位于 $scope 上。但是在这段代码里,明显篡改了用户的输入,造成“所见非所得”的后果。所以我们得把对数据的篡改去掉。再加上一些细节的优化,代码变成了这样:
$scope.$watch("newInfo", function(newValue) {
Object.assign($scope.info, newValue);
proInfoChange();
}, true);
// 把对高度和宽度手动赋值去掉了,以免和输入框的值不一致,导致“所见并非所得”
function proInfoChange () {
var newInfo = $scope.newInfo,
newW = typeof newInfo.Width === 'number' ? newInfo.Width : null,
newH = typeof newInfo.Height === 'number' ? newInfo.Height : null,
info = $scope.info;
if (newW && newH) {
if ((newW >= screenWidth )||(newH >= screenHeight )) {
var scaleX = (screenWidth / newW).toFixed(2),
scaleY = (screenHeight / newH).toFixed(2);
newInfo.Scale = info.Scale = scaleX < scaleY ? parseFloat(scaleX) : parseFloat(scaleY);
} else {
newInfo.Scale = info.Scale = 1;
}
preview.setWinfoBase(info);
sessionStorage.setItem("windowInfo", JSON.stringify(info));
dataChange();
}
}
这段代码的逻辑是这样的,先监听用户的输入,当用户修改宽高时,将其缓存到 $scope.info 中以便保存,然后再通过 proInfoChange 方法来计算出缩放比例来控制容器大小。
总结
