문제

Javascript에서 명명된 함수와 익명 함수를 사용하는 것 사이에 성능 차이가 있는지 궁금합니다.

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = function() {
        // do something
    };
}

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

첫 번째는 거의 사용되지 않는 함수로 코드를 복잡하게 만들지 않기 때문에 더 깔끔하지만 해당 함수를 여러 번 다시 선언하는 것이 중요합니까?

도움이 되었습니까?

해결책

여기서 성능 문제는 루프를 반복할 때마다 새 함수 객체를 생성하는 비용이지 익명 함수를 사용한다는 사실이 아닙니다.

for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = function() {
        // do something    
    };
}

코드 본문이 동일하고 어휘 범위에 대한 바인딩이 없음에도 불구하고 수천 개의 고유한 함수 객체를 생성하고 있습니다(폐쇄).반면에 다음은 단순히 같은 루프 전체에서 배열 요소에 대한 함수 참조:

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

루프에 들어가기 전에 익명 함수를 생성한 다음 루프 내부에 있는 배열 요소에 대한 참조만 할당하면 명명된 함수 버전과 비교할 때 성능이나 의미상 차이가 전혀 없다는 것을 알 수 있습니다.

var handler = function() {
    // do something    
};
for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = handler;
}

즉, 명명된 함수에 대해 익명을 사용하는 경우 눈에 띄는 성능 비용이 없습니다.

여담으로, 위에서 보면 다음 사이에는 차이가 없는 것처럼 보일 수 있습니다.

function myEventHandler() { /* ... */ }

그리고:

var myEventHandler = function() { /* ... */ }

전자는 함수 선언 후자는 익명 함수에 대한 변수 할당입니다.동일한 효과를 갖는 것처럼 보일 수도 있지만 JavaScript는 이를 약간 다르게 처리합니다.차이점을 이해하려면 "JavaScript 함수 선언의 모호함”.

모든 접근 방식의 실제 실행 시간은 브라우저의 컴파일러 및 런타임 구현에 따라 크게 결정됩니다.최신 브라우저 성능을 완벽하게 비교하려면 다음을 방문하세요. JS Perf 사이트

다른 팁

내 테스트 코드는 다음과 같습니다.

var dummyVar;
function test1() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = myFunc;
    }
}

function test2() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = function() {
            var x = 0;
            x++;
        };
    }
}

function myFunc() {
    var x = 0;
    x++;
}

document.onclick = function() {
    var start = new Date();
    test1();
    var mid = new Date();
    test2();
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "\n Test 2: " + (end - mid));
}

결과:
테스트 1:142ms 테스트 2 :1983ms

JS 엔진은 Test2에서 동일한 함수인 것을 인식하지 못하고 매번 컴파일하는 것으로 보입니다.

일반적인 디자인 원칙에 따라 동일한 코드를 여러 번 암시하는 것을 피해야 합니다.대신에 공통 코드를 함수로 끌어내서 여러 위치에서 해당 함수(일반적이고 잘 테스트되었으며 수정하기 쉬움)를 실행해야 합니다.

(질문에서 추론한 것과는 달리) 내부 함수를 한 번 선언하고 해당 코드를 한 번 사용하는 경우(프로그램에서 동일한 항목이 없는 경우) 익명 함수 아마 (그건 추측입니다) 컴파일러는 일반 명명된 함수와 동일한 방식으로 처리됩니다.

특정 상황에서는 매우 유용한 기능이지만 많은 상황에서는 사용해서는 안 됩니다.

큰 차이는 없을 것으로 예상되지만, 차이가 있다면 스크립팅 엔진이나 브라우저에 따라 다를 수 있습니다.

코드를 이해하기가 더 쉽다면 함수를 수백만 번 호출할 것으로 예상되지 않는 한 성능은 문제가 되지 않습니다.

익명 객체는 명명된 객체보다 빠릅니다.그러나 더 많은 함수를 호출하면 비용이 더 많이 들고 익명 함수를 사용하여 얻을 수 있는 비용 절감 효과가 무색해질 정도입니다.호출된 각 함수는 호출 스택에 추가되며, 이로 인해 작지만 적지 않은 양의 오버헤드가 발생합니다.

그러나 암호화/암호 해독 루틴이나 이와 유사하게 성능에 민감한 것을 작성하지 않는 한, 많은 사람들이 지적했듯이 빠른 코드보다 우아하고 읽기 쉬운 코드에 맞게 최적화하는 것이 항상 더 좋습니다.

잘 설계된 코드를 작성한다고 가정하면 속도 문제는 인터프리터/컴파일러를 작성하는 사람의 책임이 됩니다.

성능에 영향을 미칠 수 있는 부분은 함수 선언 작업입니다.다음은 다른 함수의 컨텍스트 내부 또는 외부에서 함수를 선언하는 벤치마크입니다.

http://jsperf.com/function-context-benchmark

Chrome에서는 함수를 외부에 선언하면 작업이 더 빨라지지만 Firefox에서는 그 반대입니다.

다른 예에서는 내부 함수가 순수 함수가 아닌 경우 Firefox에서도 성능이 부족하다는 것을 알 수 있습니다.http://jsperf.com/function-context-benchmark-3

다양한 브라우저, 특히 IE 브라우저에서 루프를 더 빠르게 만드는 것은 다음과 같은 루프입니다.

for (var i = 0, iLength = imgs.length; i < iLength; i++)
{
   // do something
}

루프 조건에 임의의 1000을 넣었지만 배열의 모든 항목을 살펴보고 싶다면 드리프트가 발생합니다.

참조는 참조하는 것보다 거의 항상 느릴 것입니다.이렇게 생각해보세요. 1 + 1을 더한 결과를 인쇄한다고 가정해 보겠습니다.어느 것이 더 의미가 있습니까?

alert(1 + 1);

또는

a = 1;
b = 1;
alert(a + b);

나는 그것이 그것을 보는 매우 단순한 방법이라는 것을 알고 있지만 그것은 예시적인 것입니다. 그렇죠?여러 번 사용할 경우에만 참조를 사용하세요. 예를 들어 다음 중 어떤 예가 더 적합한지 확인하세요.

$(a.button1).click(function(){alert('you clicked ' + this);});
$(a.button2).click(function(){alert('you clicked ' + this);});

또는

function buttonClickHandler(){alert('you clicked ' + this);}
$(a.button1).click(buttonClickHandler);
$(a.button2).click(buttonClickHandler);

두 번째는 더 많은 줄이 있더라도 더 나은 연습입니다.이 모든 내용이 도움이 되기를 바랍니다.(그리고 jquery 구문은 누구도 버리지 않았습니다)

@nickf

(댓글만 달 수 있는 담당자가 있었으면 좋았을 텐데, 이제서야 이 사이트를 발견했습니다.)

내 요점은 명명된/익명 함수와 반복에서 실행 + 컴파일의 사용 사례 사이에 혼란이 있다는 것입니다.설명했듯이 anon+named의 차이는 그 자체로는 무시할 수 있습니다. 이는 잘못된 사용 사례라는 뜻입니다.

제 생각엔 당연한 것 같지만, 그렇지 않다면 최선의 조언은 "멍청한 짓을 하지 마세요"(이 사용 사례의 지속적인 블록 이동 + 객체 생성이 그 중 하나입니다)라고 생각하며 확실하지 않다면 테스트해 보세요!

예!익명 함수는 일반 함수보다 빠릅니다.아마도 속도가 가장 중요하다면...코드 재사용보다 더 중요한 것은 익명 함수 사용을 고려하는 것입니다.

여기에 자바스크립트 및 익명 함수 최적화에 대한 정말 좋은 기사가 있습니다.

http://dev.opera.com/articles/view/efficient-javascript/?page=2

@nickf

그것은 다소 어리석은 테스트입니다. 실행을 비교하고 있습니다. 그리고 편집 분명히 방법 1(JS 엔진에 따라 N 번 컴파일)과 방법 2(한 번 컴파일)가 소요될 시간입니다.그런 방식으로 코드를 작성하여 수습 기간을 통과하는 JS 개발자는 상상할 수 없습니다.

훨씬 더 현실적인 접근 방식은 익명 할당입니다. 실제로 document.onclick 메서드에 사용하고 있는 것처럼 익명 할당은 다음과 비슷하며 실제로 anon 메서드를 약간 선호합니다.

유사한 테스트 프레임워크를 사용하여:


function test(m)
{
    for (var i = 0; i < 1000000; ++i) 
    {
        m();
    }
}

function named() {var x = 0; x++;}

var test1 = named;

var test2 = function() {var x = 0; x++;}

document.onclick = function() {
    var start = new Date();
    test(test1);
    var mid = new Date();
    test(test2);
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "ms\n Test 2: " + (end - mid) + "ms");
}

@nickf 답변에 대한 의견에서 지적했듯이:에 대한 답변

함수를 백만 번 만드는 것보다 한 번 더 빠르게 함수를 만드는 것

단순히 그렇습니다.그러나 그의 JS 성능이 보여주듯이, 이는 백만분의 일만큼 느리지 않으며 실제로 시간이 지남에 따라 더 빨라진다는 것을 보여줍니다.

나에게 더 흥미로운 질문은 다음과 같습니다.

반복되는 방법은 무엇입니까? 생성 + 실행 한 번 + 반복 생성 비교 달리다.

함수가 복잡한 계산을 수행하는 경우 함수 객체를 생성하는 데 걸리는 시간은 거의 무시할 수 있습니다.하지만 오버 헤드는 어떻습니까? 만들다 어떤 경우에는 달리다 빠르다?예를 들어:

// Variant 1: create once
function adder(a, b) {
  return a + b;
}
for (var i = 0; i < 100000; ++i) {
  var x = adder(412, 123);
}

// Variant 2: repeated creation via function statement
for (var i = 0; i < 100000; ++i) {
  function adder(a, b) {
    return a + b;
  }
  var x = adder(412, 123);
}

// Variant 3: repeated creation via function expression
for (var i = 0; i < 100000; ++i) {
  var x = (function(a, b) { return a + b; })(412, 123);
}

이것 JS 성능 함수를 한 번만 생성하는 것이 예상보다 빠르다는 것을 보여줍니다.그러나 간단한 추가와 같이 매우 빠른 작업을 수행하더라도 함수를 반복적으로 생성하는 오버헤드는 몇 퍼센트에 불과합니다.

그 차이는 아마도 함수 객체 생성이 복잡하고 실행 시간은 무시할 정도로 유지되는 경우에만 중요해질 것입니다. 예를 들어 전체 함수 본문이 if (unlikelyCondition) { ... }.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top