Понимание закрытия JavaScript и использования памяти - PullRequest
15 голосов
/ 01 июня 2011

РЕДАКТИРОВАТЬ : Это всего лишь простой пример, демонстрирующий беспокойство, которое я испытываю с гораздо более крупной программой.Я бы не использовал этот фактический код ни для чего:)

Если бы я запустил это -

<!DOCTYPE html>
<html>
<head>
<script>

function update(amount, win, data)
{
    win.innerText = 'Count is ' + amount;
    setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000);
}

window.onload = function() {

  var win = document.getElementById('item');    
  update(0, win, 0);
}
</script>
</head>

<body>
<div id="item"></div>
</body>
</html>

Вызов setTimeout предположительно создает замыкание, которое захватывает содержимое параметров в "функция обновления (сумма, выигрыш, данные).Таким образом, эти переменные сохраняются в памяти до тех пор, пока не будет вызван тайм-аут и не вернутся, чтобы они были доступны внутри вызова этой функции ...

Но эта функция создает закрытие new для следующей итерациитаймаута ... Что будет запечатлено во втором закрытии?Это просто новые копии этих переменных или те, которые составляли часть вызова функции, будут перехвачены снова в новом замыкании?

По сути это будет в конечном итогенехватка памяти из-за того, что данные в каждом закрытии становятся все больше и больше, или это безопасно и разумно?

Ответы [ 2 ]

7 голосов
/ 01 июня 2011

В моем понимании, когда замыкание создано, текущий лексический контекст связан с ним.В вашем случае это будет amount, win, data.

. Этот контекст будет использоваться при срабатывании тайм-аута для выполнения замыкания и, следовательно, повторного вызова функции update;этот вызов, хотя и может показаться таковым, не является рекурсивным, поскольку предыдущее выполнение update уже завершено и его исходный контекст (динамический, отличный от лексического) уже освобожден.(Я думаю, это важно заметить, потому что кажется, что вы беспокоитесь о некотором росте стека из-за рекурсии).

Итак, снова, update выполняется во второй раз, и снова устанавливается таймаути закрытие создано.Это закрытие связано с текущим лексическим контекстом выполнения (который все еще включает в себя только amount, win, data) и запланировано с помощью таймера.затем update заканчивается и удаляется из стека.затем снова запускается таймер, и снова вызывается обновление ...

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

4 голосов
/ 01 июня 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...