Javascript: копирование объектов, глобальные переменные и производительность - PullRequest
4 голосов
/ 04 октября 2011

У меня довольно сложный вопрос:)

В настоящее время я работаю над игрой на холсте html5. Переменные, характерные для карты игры, находятся в отдельном файле (назовем это game.js), отделенном от игрового движка (назовем его engine.js).

Я читал, что глобальные переменные медленнее используются в JS, чем локальные переменные. Поэтому в game.js я создаю глобальную переменную, которая содержит все специфичные для игры переменные. В engine.js я копирую этот глобальный объект в локальные переменные, там я удаляю этот глобальный объект.

Это работает. Но я знаю, что присвоение объектов только передает ссылку на эти объекты.

Поэтому мой вопрос: производительность будет такой, как если бы я объявил все переменные непосредственно как локальные переменные в engine.js, когда я удаляю глобальный объект в конце инициализации, или он будет медленнее, как будто мои локальные переменные в engine.js были просто ссылками на глобальный объект?

Я мог бы объявить все переменные как локальные в engine.js, но мне было бы полезно отделить то, что является специфическим для карты, если позже я захочу сделать другие карты / игры.

Например:

game.js:

Game = function() {
this.x = 16;
this.y = 16;
this.myObject = {"test": "hello", "action": "none"};
}
game = new Game();

engine.js: //...

var x = game.x;
var y = game.y;
var obj = {"test": game.myObject.test, "action": game.myObject.action};

// ...

В этом примере производительность x, y и obj будет такой же высокой, как у локальных переменных, или медленнее?

Примечание: я действительно не проверял разницу между показателями глобальных и локальных переменных, но я предполагаю, что то, что я прочитал об этом, является правильным.

Надеюсь, мой вопрос был достаточно ясным и не глупым :) Если у вас есть идеи ... Спасибо!

Ответы [ 2 ]

2 голосов
/ 04 октября 2011

Причина разницы в производительности, о которой вы говорите, заключается в том, что javascript разрешает имя переменной до значения, на которое она ссылается.Таким образом, (незначительное) временное отставание является результатом javascript поиска переменной.Когда что-то назначается по ссылке на что-то, это относится к действительному значению в памяти, а не к имени.

Например, представьте, что у вас есть переменная javascript с именем info со значением { question: null, answer: 42 },Если вы должны были сделать присваивание

info2 = info;

Вы говорите javascript, чтобы найти это значение прямо сейчас и использовать его при обращении к info2.Теперь и info, и info2 указывают на одно и то же значение (один и тот же адрес памяти).Вы не указываете javascript искать ссылку info и получать это значение каждый раз, когда вы используете info2.Это означает, что то, как вы это делаете, хорошо, так как вы просматриваете ссылки на глобальные переменные только один раз.

Обратите внимание, что javascript будет назначаться только по ссылке для неконстант, поэтому:

var a = 1;
var b = a;
var a = 2;
var b === 1; // => true

var z = { a: 1 };
var y = z;
z.a = 2;
y.a === 2; // => true

Примитивные значения являются константами, объекты - нет.

2 голосов
/ 04 октября 2011

В современных браузерах, вероятно, нет большой разницы в производительности между локальными и глобальными переменными.

Однако существует проблема с потреблением памяти - глобальные переменные сохраняются до тех пор, пока страница остается открытой, тогда как локальные переменные собирают мусор после того, как управление покидает их область действия. Использование локальных переменных снижает вероятность утечки памяти .

Обновление

Многословная дискуссия в ветке комментариев побудила меня написать тестовый скрипт для измерения различий в скорости выполнения, контрастирующих с доступом к глобальной и локальной области.

Первоначально, казалось, не было никакой разницы, и результаты варьировались без особого предпочтения тому или иному. Однако @DaveNewton предоставил контрпример, который последовательно показывает лучшую производительность для локальных переменных на порядок.


Firefox 7

Миллисекунды, используемые для 20000 глобальных обращений: 132

Миллисекунды, используемые для 20000 локальных обращений: 159

Internet Explorer 9

Миллисекунды, используемые для 20000 глобальных обращений: 1750

Миллисекунды, используемые для 20000 локальных обращений: 1699

Google Chrome 14

Миллисекунды, используемые для 20000 глобальных обращений: 46

Миллисекунды, используемые для 20000 локальных обращений: 55

Сам тестовый скрипт

<html>
<head>
<script type="text/javascript">

function t() {

var test = function () {}
test.issue = new String("hello");

var start = new Date().getTime();
(function() {
    (function() {
        (function() {
            (function() {
                (function() {
                    (function() {
                        (function() {
                            var a = document.getElementById("a");
                            for (var i = 0; i < 20000; i++) {
                                a.innerHTML = test.issue.toString();
                            }
                            a = null;
                        })();
                    })();
                })();
            })();
        })();
    })();
})();
var stop = new Date().getTime();
document.getElementById("a").innerHTML = "Milliseconds used for 20000 global accesses: " + (stop - start);


var start = new Date().getTime();
(function() {
    (function() {
        (function() {
            (function() {
                (function() {
                    (function() {
                        (function() {
                            var c = document.getElementById("c");
                            var testx = {};
                            testx.issue = new String("hello");
                            for (var i = 0; i < 20000; i++) {
                                c.innerHTML = testx.issue.toString();
                            }
                            c = null;
                        })();
                    })();
                })();
            })();
        })();
    })();
})();
var stop = new Date().getTime();
document.getElementById("c").innerHTML = "Milliseconds used for 20000 local accesses: " + (stop - start);

}

window.onload = function () {
    document.getElementById('b').onclick = t;
}

</script>
</head>
<body>
<div align="center"><button id="b">Run Test</button></div>
<div id="a"></div>
<div id="c"></div>
</body>

</html>

Контрпример, демонстрирующий более быстрый доступ к локальным переменным.

var t0 = new Date();
var i; 
for (i=0; i<10000000; i++); 
var t1 = new Date(); 
function count() { for (var i=0; i<10000000; i++); } 
var t2 = new Date(); 
count(); 
var t3 = new Date(); 
d = document; 
d.write('Without local variables = ', t1-t0, '<br />'); 
d.write('With local variables = ', t3-t2, '<br />');
...