>  기사  >  웹 프론트엔드  >  JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

亚连
亚连원래의
2018-05-18 15:39:541444검색

JS 코드의 실행 효율성은 종종 페이지 성능에 직접적인 영향을 미칩니다. 때로는 동일한 기능을 달성하기 위해 서로 다른 JS 코드가 효율성에 많은 차이를 보이는 경우도 있습니다. 고급 우리가 사용하는 대부분의 브라우저는 우리에게 최적화되어 있지만 중국에는 여전히 사악한 IE6이 많이 존재하므로 이를 고려해야 합니다. JS 코드 최적화에 관해서는 실제로 많은 상황이 있는데, 그 중 일부는 상대적으로 작은 영향을 미치고 일부는 더 심각합니다. 이 기사에서는 참고할 수 있도록 심각한 영향을 미치는 몇 가지 상황을 나열합니다.

1. 스트링 스플라이싱

스트링 스플라이싱은 우리 개발에서 자주 접하기 때문에 +=를 사용하여 문자열을 직접 스플라이싱하는 데 익숙합니다. 사실 이런 방식의 스플라이싱은 효율성이 매우 낮습니다. . 배열의 결합 방법을 사용하여 문자열을 연결하는 영리한 방법을 사용할 수 있습니다.

<p class="one" id="one"></p>   
<input type="button" value="效率低" onclick="func1()" />   
<input type="button" value="效率高" onclick="func2()" /> //效率低的   function func1(){   
    var start = new Date().getTime();   
    var template = "";   
    for(var i = 0; i < 10000; i++){   
        template += "<input type=&#39;button&#39; value=&#39;a&#39;>";   
    }   
    var end = new Date().getTime();   
    document.getElementById("one").innerHTML = template;   
    alert("用时:" + (end - start) + "毫秒");   }   //效率高的   function func2(){   
    var start = new Date().getTime();   
    var array = [];   
    for(var i = 0; i < 10000; i++){   
        array[i] = "<input type=&#39;button&#39; value=&#39;a&#39;>";   
    }   
    var end = new Date().getTime();   
    document.getElementById("one").innerHTML = array.join("");   
    alert("用时:" + (end - start) + "毫秒");   }

다른 브라우저에서 실행을 살펴보겠습니다.

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

IE6에서는 차이가 매우 분명하다는 것을 알 수 있습니다. 실제로 이러한 상황은 IE의 상위 버전에서도 매우 분명합니다. Firefox에서의 차이점은 반대로 두 번째 유형의 상대적 효율성은 훨씬 낮지만 그 차이는 약 2ms에 불과하며 Chrome은 Firefox와 유사합니다. 그런데 배열에 요소를 추가할 때 push라는 기본 방식을 선호하는 분들이 많습니다. 실제로는 arr[i]나 arr[arr.length]를 직접 사용하는 것이 더 빠릅니다. 10000. 다중 루프의 경우 IE 브라우저에서는 10밀리초 이상의 차이가 발생합니다.

2. for 루프

for 루프는 우리가 자주 접하는 상황입니다. 다음 예를 살펴보겠습니다.

<input type="button" value="效率低" onclick="func1()" />   
<input type="button" value="效率高" onclick="func2()" /> 
var arr = [];   
for(var i = 0; i < 10000; i++){   
    arr[i] = "<p>" + i + "</p>";   
}   
document.body.innerHTML += arr.join("");   
//效率低的   function func1(){   
    var ps = document.getElementsByTagName("p");   
    var start = new Date().getTime();   
    for(var i = 0; i < ps.length; i++){   
        //"效率低"   
    }   
    var end = new Date().getTime();   
    alert("用时:" + (end - start) + "毫秒");   
}   
//效率高的   function func2(){   
    var ps = document.getElementsByTagName("p");   
    var start = new Date().getTime();   
    for(var i = 0, len = ps.length; i < len; i++){   
        //"效率高"   
    }   
    var end = new Date().getTime();   
    alert("用时:" + (end - start) + "毫秒");   
}

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

위 표에서 볼 수 있듯이 IE6.0에서는 차이가 매우 큽니다. 당연하며, Firefox와 Chrome에서는 거의 차이가 없습니다. IE6.0에서 이런 일이 발생하는 이유는 주로 for 루프가 첫 번째 경우에는 매번 길이가 계산되기 때문입니다. 하지만 처음부터 길이를 계산해서 변수에 저장하기 때문에 실행 효율성이 더 높습니다. 따라서 for 루프를 사용할 때, 특히 길이를 계산해야 하는 경우에는 변수에 저장하기 시작해야 합니다. 그러나 길이를 얻는 한 그렇게 뚜렷한 차이는 없습니다. 배열을 연산하고 배열의 길이를 얻는다면 두 가지 작성 방법은 실제로 유사합니다.

<input type="button" value="效率低" onclick="func1()" />   
<input type="button" value="效率高" onclick="func2()" />  
var arr2 = [];   
for(var i = 0; i < 10000; i++){   
    arr2[i] = "<p>" + i + "</p>";   
}   
//效率低的   function func1(){   
    var start = new Date().getTime();   
    for(var i = 0; i < arr2.length; i++){   
        //"效率低"   
    }   
    var end = new Date().getTime();   
    alert("用时:" + (end - start) + "毫秒");   
}   
//效率高的   function func2(){   
    var start = new Date().getTime();   
    for(var i = 0, len = arr2.length; i < len; i++){   
        //"效率高"   
    }   
    var end = new Date().getTime();   
    alert("用时:" + (end - start) + "毫秒");   
}

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

위 표에서 볼 수 있듯이 그냥 배열이라면 두 가지 작성 방법이 거의 동일하다는 것을 알 수 있습니다. 실제로 루프를 100,000배로 늘려도 그 차이는 약간에 불과합니다. milliseconds 이므로 배열의 경우에도 마찬가지라고 생각합니다. for 루프의 최적화에 관해서도 어떤 사람들은 많은 점을 제시했는데, 어떤 사람들은 -=1을 사용하거나 큰 것에서 작은 것으로 반복하는 등의 작업이 완전히 불필요하다고 생각합니다. 실제 상황에서는 한마디로 컴퓨터 수준에서는 작은 변화일 뿐이지만 코드의 가독성이 크게 떨어지므로 실제로 얻을 가치가 없습니다.

3. 페이지 다시 그리기 줄이기

페이지 다시 그리기 줄이기는 본질적으로 JS 자체의 최적화는 아니지만, JS로 인해 발생하는 경우가 많고, 다시 그리기가 페이지 성능에 심각한 영향을 미치는 경우가 많기 때문에 꼭 필요한 부분이 나옵니다. 다음 예는 다음과 같습니다.

<p id="demo"></p>   
<input type="button" value="效率低" onclick="func1()" />   
<input type="button" value="效率高" onclick="func2()" /> 
var str = "<p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p><p>这是一个测试字符串</p>";   
//效率低的   function func1(){   
    var obj = document.getElementById("demo");   
    var start = new Date().getTime();   
    for(var i = 0; i < 100; i++){   
        obj.innerHTML += str + i;   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");   
}   
//效率高的   function func2(){   
    var obj = document.getElementById("demo");   
    var start = new Date().getTime();   
    var arr = [];   
    for(var i = 0; i < 100; i++){   
        arr[i] = str + i;   
    }   
    obj.innerHTML = arr.join("");   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

이것은 단순히 100주기만에 놀라운 결과라는 것입니다. 어떤 브라우저이든지 간에 우리는 여기서도 큰 차이가 있다는 것을 발견했습니다. 실제로 IE6의 실행 효율성은 Firefox보다 훨씬 좋습니다. Firefox는 페이지 다시 그리기 측면에서 어떠한 최적화도 수행하지 않았음을 알 수 있습니다. 일반적으로 페이지 다시 그리기에 영향을 미치는 것은 innerHTML 뿐만이 아니라는 점에 유의해야 합니다. 요소의 스타일, 위치 등을 변경하면 페이지 다시 그리기가 트리거되므로 평소에는 이에 주의해야 합니다.

4. 범위 체인 검색 횟수 줄이기
js 코드가 실행될 때 변수나 함수에 액세스해야 하는 경우 현재 실행 환경의 범위 체인을 순회해야 하며 순회가 필요하다는 것을 알고 있습니다. 이것부터 시작합니다. 스코프 체인의 프런트 엔드는 전역 실행 환경까지 한 단계씩 뒤로 이동하므로 여기서는 종종 상황이 발생합니다. 즉, 전역 환경의 변수 개체에 자주 액세스해야 하는 경우 항상 현재 범위 체인에서 전역 환경의 변수 개체에 액세스하려면 도메인 체인을 수준별로 탐색하는 데 시간이 많이 걸립니다.

<p id="demo"></p>   
<input id="but1" type="button" onclick="func1()" value="效率低"/>   
<input id="but2" type="button" onclick="func2()" value="效率高"/>   
function func1(){   
    var start = new Date().getTime();   
    for(var i = 0; i < 10000; i++){   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
        var but1 = document.getElementById("but1");   
        var but2 = document.getElementById("but2");   
        var inputs = document.getElementsByTagName("input");   
        var ps = document.getElementsByTagName("p");   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");   
}   
function func2(){   
    var start = new Date().getTime();   
    var doc = document;   
    for(var i = 0; i < 10000; i++){   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
        var but1 = doc.getElementById("but1");   
        var but2 = doc.getElementById("but2");   
        var inputs = doc.getElementsByTagName("input");   
        var ps = doc.getElementsByTagName("p");   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");

上面代码中,第二种情况是先把全局对象的变量放到函数里面先保存下来,然后直接访问这个变量,而第一种情况是每次都遍历作用域链,直到全局环境,我们看到第二种情况实际上只遍历了一次,而第一种情况却是每次都遍历了,所以我们看看其执行结果: 

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

从上表中可以看出,其在IE6下差别还是非常明显的,而且这种差别在多级作用域链和多个全局变量的情况下还会表现的非常明显。

5、避免双重解释

双重解释的情况也是我们经常会碰到的,有的时候我们没怎么考虑到这种情况会影响到效率,双重解释一般在我们使用eval、new Function和setTimeout等情况下会遇到,我们看看下面的例子:

<p id="demo"></p>   
<input id="but1" type="button" onclick="func1()" value="效率低"/>   
<input id="but2" type="button" onclick="func2()" value="效率高"/>   
var sum, num1 = 1, num2 = 2;   
function func1(){   
    var start = new Date().getTime();   
    for(var i = 0; i < 10000; i++){   
        var func = new Function("sum+=num1;num1+=num2;num2++;");   
        func();   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");   
}   
function func2(){   
    var start = new Date().getTime();   
    for(var i = 0; i < 10000; i++){   
        sum+=num1;   
        num1+=num2;   
        num2++;   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");   
}

第一种情况我们是使用了new Function来进行双重解释,而第二种是避免了双重解释,我们看看在不同浏览器下的表现: 

 JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

可以看到,在所有的浏览器中,双重解释都是有很大开销的,所以在实际当中要尽量避免双重解释。

感谢”SeaSunK”对第四点测试报告错误的指正,现在已经修改过来了。至于最后一点提出的func1每次都初始化,没有可比性,所以我给换了eval,结果发现,在IE6.0下还是有影响,而且在Firefox下,使用eval对效率的影响程度更加厉害,在Firefox下,如果10000次循环,需要十多秒的时间,所以我把循环都变成了1000次。看代码和报告。

var sum, num1 = 1, num2 = 2;   
function func1(){   
    var start = new Date().getTime();   
    for(var i = 0; i < 1000; i++){   
        eval("sum+=num1;num1+=num2;num2++;");   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");   
}   
function func2(){   
    var start = new Date().getTime();   
    for(var i = 0; i < 1000; i++){   
        sum+=num1;   
        num1+=num2;   
        num2++;   
    }   
    var end = new Date().getTime();   
    alert("用时 " + (end - start) + " 毫秒");

JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JavaScript设计模式系列一:工厂模式

JavaScript设计模式系列二:单例模式

JavaScript设计模式系列三:建造者模式

위 내용은 JS 코드를 최적화하는 방법 정보(그래픽 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.