it-swarm-ko.tech

익명 함수 사용이 성능에 영향을 줍니까?

Javascript에서 명명 된 함수와 익명 함수를 사용하는 것 사이에 성능 차이가 있습니까?

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

vs

function myEventHandler() {
    // do something
}

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

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

83
nickf

여기서 성능 문제는 익명 함수를 사용한다는 사실이 아니라 루프가 반복 될 때마다 새 함수 객체를 작성하는 비용입니다.

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

코드 본문이 동일하고 어휘 범위 ( closure )에 바인딩되지 않더라도 수천 개의 개별 함수 객체를 작성하고 있습니다. 반면에 다음은 루프 전체에서 배열 요소에 same 함수 참조를 지정하기 때문에 더 빠릅니다.

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 사이트 를 방문하십시오.

83
Atif Aziz

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

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에서 동일한 기능임을 인식하지 못하고 매번 컴파일합니다.

21
nickf

일반적인 설계 원칙으로 동일한 코드를 여러 번 암시하지 않아야합니다. 대신 공통 코드를 함수로 들어 올리고 여러 위치에서 해당 기능 (일반 테스트, 수정이 용이함)을 실행해야합니다.

(당신의 질문에서 추론하는 것과는 달리) 내부 함수를 한 번 선언하고 해당 코드를 한 번 사용하고 (프로그램에서 다른 것이 동일하지 않은 경우) 익명 함수 아마 (추측 사람들) 컴파일러에서 일반 명명 된 함수와 동일한 방식으로 처리합니다.

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

2
Tom Leys

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

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

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

다른 예에서 내부 함수가 순수한 함수가 아닌 경우 Firefox에서도 성능이 떨어집니다. http://jsperf.com/function-context-benchmark-

1
Pablo Estornut

나는 큰 차이를 기대하지는 않지만 스크립트 엔진이나 브라우저에 따라 다를 수 있습니다.

코드를 이해하기 쉽다면, 수백만 번 함수를 호출하지 않는 한 성능은 문제가되지 않습니다.

1
Joe Skora

익명의 개체는 명명 된 개체보다 빠릅니다. 그러나 더 많은 함수를 호출하면 비용이 많이 들고 익명 함수를 사용하여 얻을 수있는 비용을 어느 정도 줄일 수 있습니다. 호출 된 각 함수는 호출 스택에 추가되므로 작지만 사소한 양의 오버 헤드가 발생합니다.

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

잘 설계된 코드를 작성한다고 가정하면, 속도 문제는 통역사/컴파일러 작성 담당자의 책임입니다.

1
pcorcoran

nick

그것은 다소 치명적인 테스트이지만, 방법 1 (N 컴파일, JS 엔진에 따라 다름)과 메소드 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");
}
0
annakata

nick

(저는 의견을 말한 담당자가 있지만이 사이트 만 찾았습니다)

내 요점은 명명 된/익명의 함수와 반복에서 실행 + 컴파일의 유스 케이스 사이에 혼란이 있다는 것입니다. 내가 설명했듯이, anon + named의 차이점은 그 자체로는 무시할 만합니다. 사용 사례가 잘못되었다고 말하고 있습니다.

나에게는 분명한 것처럼 보이지만 최선의 조언은 "멍청한 일을하지 마십시오"(이 유스 케이스의 일정한 블록 이동 + 객체 생성이 하나임)이고 확실하지 않은 경우 테스트하십시오!

0
annakata

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

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

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

0
Christopher Tokar

참조는 항상 참조하는 것보다 느릴 것입니다. 이 방법으로 생각하십시오-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 구문은 아무도 버리지 않았습니다)

0
matt lohkamp

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

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

단순히 그렇습니다. 그러나 그의 JS perf가 보여 주듯이, 그것은 백만 배나 느리지 않아 실제로 시간이 지남에 따라 더 빠릅니다.

나에게 더 흥미로운 질문은 :

반복 된 create + run 은 한 번 생성 + 반복되는 run .

함수가 복잡한 계산을 수행하는 경우 함수 객체를 만드는 시간은 거의 무시할 수 있습니다. 그러나 run 이 빠른 경우 create 의 오버 헤드는 어떻습니까? ? 예를 들어 :

// 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 Perf 는 함수를 한 번만 만드는 것이 예상보다 빠르다는 것을 보여줍니다. 그러나 간단한 추가와 같이 매우 빠른 조작으로도 함수를 반복적으로 작성하는 오버 헤드는 몇 퍼센트에 불과합니다.

예를 들어 전체 함수 본문이 if (unlikelyCondition) { ... }에 싸여있는 경우 무시할 수있는 런타임을 유지하면서 함수 객체를 만드는 것이 복잡한 경우에만 차이가 커질 수 있습니다.

0
bluenote10

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

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

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

0
Sarhanis