前端小白的日常——一次代码优化

352 阅读3分钟

先看原始代码

其实这是一个老项目,本可以只解决 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 方法来计算出缩放比例来控制容器大小。

总结

在代码大全看到过一句话:“每次到来都使营地更整洁”。个人的理解是,我们每次编辑一个文件,都不要使其复杂度增加,而且要尽可能地使文件更加清晰整洁。我发现很多人常常会因为写一些重复的业务代码而感觉没有进步。其实哪怕是简单的重复性工作,只要我们每一次都精益求精,每一次都比上一次要好一点点,超越自己一点点,日积月累就是会有质的飞跃。