Programing

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

lottogame 2020. 9. 25. 08:10
반응형

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


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;
}

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


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

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

코드 본문이 같고 어휘 범위 ( closure )에 대한 바인딩이 없더라도 수천 개의 고유 한 함수 개체를 만들고 있습니다. 반면에 다음은 루프 전체의 배열 요소에 동일한 함수 참조를 할당하기 때문에 더 빠릅니다 .

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


일반적인 디자인 원칙으로 동일한 코드를 여러 번 구현하지 않아야합니다. 대신 일반적인 코드를 함수로 끌어내어 여러 위치에서 해당 (일반적이고 잘 테스트되었으며 수정하기 쉬운) 함수를 실행해야합니다.

If (unlike what you infer from your question) you are declaring the internal function once and using that code once (and have nothing else identical in your program) then an anonomous function probably (thats a guess folks) gets treated the same way by the compiler as a normal named function.

Its a very useful feature in specific instances, but shouldn't be used in many situations.


I wouldn't expect much difference but if there is one it will likely vary by scripting engine or browser.

If you find the code easier to grok, performance is a non-issue unless you expect to call the function millions of times.


Anonymous objects are faster than named objects. But calling more functions is more expensive, and to a degree which eclipses any savings you might get from using anonymous functions. Each function called adds to the call stack, which introduces a small but non-trivial amount of overhead.

But unless you're writing encryption/decryption routines or something similarly sensitive to performance, as many others have noted it's always better to optimize for elegant, easy-to-read code over fast code.

Assuming you are writing well-architected code, then issues of speed should be the responsibility of those writing the interpreters/compilers.


Where we can have a performance impact is in the operation of declaring functions. Here is a benchmark of declaring functions inside the context of another function or outside:

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

In Chrome the operation is faster if we declare the function outside, but in Firefox it's the opposite.

In other example we see that if the inner function is not a pure function, it will have a lack of performance also in Firefox: http://jsperf.com/function-context-benchmark-3


What will definitely make your loop faster across a variety of browsers, especially IE browsers, is looping as follows:

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

You've put in an arbitrary 1000 into the loop condition, but you get my drift if you wanted to go through all the items in the array.


a reference is nearly always going to be slower then the thing it's refering to. Think of it this way - let's say you want to print the result of adding 1 + 1. Which makes more sense:

alert(1 + 1);

or

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

I realize that's a really simplistic way to look at it, but it's illustrative, right? Use a reference only if it's going to be used multiple times - for instance, which of these examples makes more sense:

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

or

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

The second one is better practice, even if it's got more lines. Hopefully all this is helpful. (and the jquery syntax didn't throw anyone off)


@nickf

(wish I had the rep to just comment, but I've only just found this site)

My point is that there is confusion here between named/anonymous functions and the use case of executing + compiling in an iteration. As I illustrated, the difference between anon+named is negligible in itself - I'm saying it's the use case which is faulty.

It seems obvious to me, but if not I think the best advice is "don't do dumb things" (of which the constant block shifting + object creation of this use case is one) and if you aren't sure, test!


YES! Anonymous functions are faster than regular functions. Perhaps if speed is of the utmost importance... more important than code re-use then consider using anonymous functions.

There is a really good article about optimizing javascript and anonymous functions here:

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


@nickf

That's a rather fatuous test though, you're comparing the execution and compilation time there which is obviously going to cost method 1 (compiles N times, JS engine depending) with method 2 (compiles once). I can't imagine a JS developer who would pass their probation writing code in such a manner.

A far more realistic approach is the anonymous assignment, as in fact you're using for your document.onclick method is more like the following, which in fact mildly favours the anon method.

Using a similar test framework to yours:


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");
}

As pointed out in the comments to @nickf answer: The answer to

Is creating a function once faster than creating it a million times

is simply yes. But as his JS perf shows, it is not slower by a factor of a million, showing that it actually gets faster over time.

The more interesting question to me is:

How does a repeated create + run compare to create once + repeated run.

If a function performs a complex computation the time to create the function object is most likely negligible. But what about the over head of create in cases where run is fast? For instance:

// 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);
}

This JS Perf shows that creating the function just once is faster as expected. However, even with a very quick operation like a simple add, the overhead of creating the function repeatedly is only a few percent.

The difference probably only becomes significant in cases where creating the function object is complex, while maintaining a negligible run time, e.g., if the entire function body is wrapped into an if (unlikelyCondition) { ... }.

참고URL : https://stackoverflow.com/questions/80802/does-use-of-anonymous-functions-affect-performance

반응형