Javascript setinterval()
Содержание:
Using setTimeout to make a countdown
The final example shows a countdown where the numbers count down from 10 to 0 updating every second. This is done by decrementing the counter number and then calling setTimeout again at the end of the timeout function call.
Here’s the example code:
<script language="Javascript">
var countdown;
var countdown_number;
function countdown_init() {
countdown_number = 11;
countdown_trigger();
}
function countdown_trigger() {
if(countdown_number > 0) {
countdown_number--;
document.getElementById('countdown_text').innerHTML = countdown_number;
if(countdown_number > 0) {
countdown = setTimeout('countdown_trigger()', 1000);
}
}
}
function countdown_clear() {
clearTimeout(countdown);
}
</script>
<div>
<input type="button" value="start countdown" onclick="countdown_init()" />
<input type="button" value="stop countdown" onclick="countdown_clear()" />
</div>
<div id="countdown_text">Placeholding text</div>
And here it is in action, again nothing that if you reading this in a feed reader you may need to click through to the actual post to see this working.
var countdown;
var countdown_number;
function countdown_init() {
countdown_number = 11;
countdown_trigger();
}
function countdown_trigger() {
if(countdown_number > 0) {
countdown_number—;
document.getElementById(‘countdown_text’).innerHTML = countdown_number;
if(countdown_number > 0) {
countdown = setTimeout(‘countdown_trigger()’, 1000);
}
}
}
function countdown_clear() {
clearTimeout(countdown);
}
Placeholding text
Özet
- ve metodları ‘ın düzenli olarak ms aralıklar ile çalışmasını sağlar.
- Çalışmayı durdurmak için fonksiyonları metodundan dönen değerler ile çağırılmalıdır.
- İç içe çağrısı kullanmak ‘e göre daha esnektir. Ayrıca bu şekilde aralarda en kısa süre beklemesini sağlar.
- 0 gecikmeli zamanlayıcı ise zamanlayıcıyı olabildiğince çabuk fakat o anki koddan sonra çağırılacak şekilde zamanlar.
‘ın bazı kullanım durumları:
- CPU-aç görevleri parçalara ayırmak için, böylece kod sürekli tepki verebilir.
- Böylece görev devam ederken tarayıcının başka işlere ( ilerleme çubuğu ) zaman ayırır.
Tüm zamanlama metodları tam olarak gecikmeyi garantilemez. Zamanlayıcıda bu varsayımın üzerine birşey inşa etmeyin.
Örneğin, tarayıcı zamanı birçok nedenden ötürü yavaşlayabilir:
- İşlemcinin yükü artarsa.
- Tarayıcının tab’ı arka plana alındıysa.
- Laptop batarya ile çalışıyorsa.
Bunların hepsi tarayıcı zamanına etki eder. Aralardaki gecikme 300ms ile 1000ms arasında değişebilir. Tabi tarayıcı ve özellikleri de bu konuda etkin rol oynar.
setTimeout and clearTimeout Example
setTimeout returns a value which stores a reference to the timer. The timer can then be cleared using the clearTimeout function. This is done in the following example:
<script language="Javascript">
var timeout;
function timeout_trigger() {
document.getElementById('timeout_text').innerHTML = 'The timeout has been triggered';
}
function timeout_clear() {
clearTimeout(timeout);
document.getElementById('timeout_text').innerHTML = 'The timeout has been cleared';
}
function timeout_init() {
timeout = setTimeout('timeout_trigger()', 3000);
document.getElementById('timeout_text').innerHTML = 'The timeout has been started';
}
</script>
<div>
<input type="button" value="test timeout" onclick="timeout_init()" />
<input type="button" value="clear timeout" onclick="timeout_clear()" />
</div>
<div id="timeout_text"></div>
When timeout_init() is called, the timeout reference is stored in the «timeout» variable. The name of the variable can be whatever you want, but it needs to be in the global scope, hence the «var timeout;» declaration at the start of the code.
Clicking the «test timeout» button starts the timer and the «clear timeout» button clears the timeout at the end. Here it is in action. Again, if you reading this post in a feed reader you may need to click through to the actual post to see this working.
function timeout_trigger() {
document.getElementById(‘timeout_text’).innerHTML = ‘The timeout has been triggered‘;
}
function timeout_clear() {
clearTimeout(timeout);
document.getElementById(‘timeout_text’).innerHTML = ‘The timeout has been cleared‘;
}
function timeout_init() {
timeout = setTimeout(‘timeout_trigger()’, 3000);
document.getElementById(‘timeout_text’).innerHTML = ‘The timeout has been started‘;
}
Placeholding text
Summary
- Methods and allow us to run the once/regularly after milliseconds.
- To cancel the execution, we should call with the value returned by .
- Nested calls are a more flexible alternative to , allowing us to set the time between executions more precisely.
- Zero delay scheduling with (the same as ) is used to schedule the call “as soon as possible, but after the current script is complete”.
- The browser limits the minimal delay for five or more nested calls of or for (after 5th call) to 4ms. That’s for historical reasons.
Please note that all scheduling methods do not guarantee the exact delay.
For example, the in-browser timer may slow down for a lot of reasons:
- The CPU is overloaded.
- The browser tab is in the background mode.
- The laptop is on battery.
All that may increase the minimal timer resolution (the minimal delay) to 300ms or even 1000ms depending on the browser and OS-level performance settings.
Управление временным континуумом с Node.js
API Node.js предоставляет несколько способов планирования кода, который нужно
выполнить, в какой-то момент в будущем. Приведенные ниже функции могут показатья знакомыми, так как
они доступны в большинстве браузеров, но Node.js на самом деле предоставляет
свою реализацию этих методов. Таймеры очень тесно интегрируются с системой, и, несмотря на то,
что API Node.js отражает API браузера, все равно имеются некоторые различия в реализации.
«Когда я скажу» Выполнение ~
может использоваться для планирования выполнения кода после назначенного
количества миллисекунд. Эта функция аналогична из JavaScript API браузера, однако строка кода не может передаваться
в качестве аргумента для выполнения.
первым параметром принимает функцию, которую нужно выполнить, и задержку в миллисекундах,
как число, в качестве второго параметра. Также можно перечислить дополнительные аргументы и они
будут переданы функции. Вот пример этого:
Функция выполнится через время, максимально приближенное к
1500 миллисекундам (или 1.5 секунды), из-за вызова .
Нельзя полагаться на то, что тайм-аут выполнится после этого точного количества миллисекунд.
Это связано с тем, что другой исполняемый код, который блокирует или удерживает цикл событий,
отодвигает выполнение тайм-аута на задний план. Единственной гарантией является то, что
тайм-аут не будет выполнен раньше, чем заданный интервал.
возвращает объект , который можно использовать в качестве ссылки
на тайм-аут, который был установлен. Этот объект можно использовать для отмены тайм-аута (см. ниже), а также для изменения поведения при выполнении (см. ниже).
«Сразу после этого» Выполнение ~
выполнит код в конце текущего цикла событий.
Этот код будет выполняться после любых операций ввода-вывода в текущем цикле событий и
перед любым запланированными таймерами для следующего цикла событий. Такое выполнение кода
можно рассматривать как «сразу после этого», то есть любой код, следующий за вызовом
функции , будет выполняться до аргумента функции .
Первым аргументом будет функция, которую нужно выполнить. Все последующие
аргументы будут переданы функции при ее выполнении. Вот пример:
Функция, переданная в , будет выполнена после того,
как будет выполнен весь исполняемый код, и в консоли мы увидим следующее:
возвращает объект , который можно использовать для отмены
запланированного immediate (см. ниже).
Примечание: Не путайте и . Между ними есть
несколько основных различий. Во-первых, выполнится перед любыми ,
а также перед любыми запланированными операциями ввода/вывода. Во-вторых, не подлежит
отмене, имеется в виду, что после того как вы запланировали выполнение кода с помощью ,
то его выполнение не может быть приостановлено, также как и с обычной функцией. Обратитесь к
, чтобы лучше понять
работу .
«Бесконечный цикл» Выполнение ~
Если у вас есть код, который нужно выполнить несколько раз, то можно использовать
для этого . принимает параметром функцию, которая будет
выполняться бесконечное количество раз с заданным интервалом в миллисекундах, сам интервал передается
вторым параметром. Как и в случае с можно передавать дополнительные аргументы,
эти аргументы будут переданы функции при вызове. Также как и с , задержка не может
быть гарантирована из-за операций, которые могут удерживать цикл событий, следовательно, нужно
рассматривать эту задержку как приблизительную. Смотрите пример ниже:
В примере выше будет выполняться каждые 1500 миллисекунд
или 1.5 секунд, до тех пор, пока ее не остановят (см. ниже).
, также как и возвращает объект , который
можно использовать в качестве ссылки для изменения установленного интервала.
Используем requestAnimationFrame
Этому методу должна быть передана колбэк функция, которая отвечает за отрисовку одного кадра вашей анимации. Для того, чтобы создать полную анимацию, вам понадобится сделать этот колбэк рекурсивным.
Временная метка с высоким разрешением DOMHighResTimeStamp передаётся колбэку. Вам не понадобится всегда это использовать, но это может быть довольно полезным для некоторых анимаций.
Пример ниже показывает то, как настроить рекурсивную функцию, которая использует .
// Анимируемfunction animate(highResTimestamp) {requestAnimationFrame(animate);// Анимируем что-нибудь…}// Запускаем анимацию.requestAnimationFrame(animate);
Стоит упомянуть, что у вас есть только 16.67 миллисекунд, чтобы отрендерить каждый кадр. С точки зрения времени это не очень хорошо, так что вам нужно быть осторожным с тем, что вы хотите выполнить внутри колбэк функции. Если ваш кадр требует больше 16.67 секунд на обработку, то анимация может выйти не совсем плавной.
отдаст , который может быть использован для отмены запланированного кадра анимации.
var requestID = requestAnimationFrame(animate);
Zero delay setTimeout
There’s a special use case: , or just .
This schedules the execution of as soon as possible. But the scheduler will invoke it only after the currently executing script is complete.
So the function is scheduled to run “right after” the current script.
For instance, this outputs “Hello”, then immediately “World”:
The first line “puts the call into calendar after 0ms”. But the scheduler will only “check the calendar” after the current script is complete, so is first, and – after it.
There are also advanced browser-related use cases of zero-delay timeout, that we’ll discuss in the chapter Event loop: microtasks and macrotasks.
Zero delay is in fact not zero (in a browser)
In the browser, there’s a limitation of how often nested timers can run. The says: “after five nested timers, the interval is forced to be at least 4 milliseconds.”.
Let’s demonstrate what it means with the example below. The call in it re-schedules itself with zero delay. Each call remembers the real time from the previous one in the array. What do the real delays look like? Let’s see:
First timers run immediately (just as written in the spec), and then we see . The 4+ ms obligatory delay between invocations comes into play.
The similar thing happens if we use instead of : runs few times with zero-delay, and afterwards with 4+ ms delay.
That limitation comes from ancient times and many scripts rely on it, so it exists for historical reasons.
For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like for Node.js. So this note is browser-specific.
Wrapping Up
One potential caveat to be aware of is the fact that is asynchronous. It queues the function reference it receives to run once the current call stack has finished executing. It doesn’t, however, execute concurrently, or on a separate thread (due to JavaScript’s single-threaded nature).
Although we’re calling with a zero second delay, the numbers are still logged out of order. This is because when ‘s timer has expired, the JavaScript engine places its callback function in a queue, behind the other statements, to be executed.
If you’d like to learn more about what happens when JavaScript runs, I highly recommend this video from JSConf 2014: What the heck is the event loop anyway?
requestAnimationFrame()
You should also be aware of requestAnimationFrame. This method tells the browser that you wish to call a specified function before the next repaint.
When making animations, we should favor over using , as it will fire roughly sixty times a second, as opposed to , which is called after a minimum of milliseconds. By using we can avoid changing something twice between two frame updates.
Here’s an example of how to use to animate a element across the screen:
You could, of course, achieve the same thing using :
But as mentioned, using offers various advantages, such as allowing the browser to make optimizations and stopping animations in inactive tabs.
See the Pen
Animation with requestAnimationFrame by SitePoint (@SitePoint)
on CodePen.
jQuery.delay()
Finally, I’d like to clear up any confusion between the use of the native JavaScript function and jQuery’s delay method.
The method is meant specifically for adding a delay between methods in a given jQuery queue. There is no possibility to cancel the delay. For example, if you wanted to fade an image into view for one second, have it visible for five seconds, and then fade it out for a period of one second, you could do the following:
is best used for everything else.
Note: if you need to repeatedly execute code after a specified delay, then is more suited to the job. You can read more about this function here.
Сопутствующие проблемы и “this”
Код, исполняемый setTimeout, запускается отдельно от функции, которой он был вызван. Из-за этого мы сталкиваемся с определенными проблемами, в качестве решения которых можно использовать ключевое слово this.
var person = {
firstName: "Jim",
introduce: function(){
console.log("Hi, I'm " + this.firstName);
}
};
person.introduce();
// Outputs: Hi, I'm Jim
setTimeout(person.introduce, 50);
// Outputs: Hi, I'm undefined
Причина такого вывода кроется в том, что в первом примере this ведет к объекту person, а во втором примере — указывает на глобальный объект window, у которого отсутствует свойство firstName.
Чтобы избавиться от этой нестыковки, можно воспользоваться несколькими методами:
Принудительно установить значение this
Это можно сделать при помощи bind() – метода, который создает новую функцию, которая при вызове в качестве значения ключа this использует определенное значение. В нашем случае — указанный объект person. Это в результате дает нам:
setTimeout(person.introduce.bind(person), 50);
Примечание: метод bind был представлен в ECMAScript 5, а значит, что он будет работать только в современных браузерах. В других при его применении вы получите ошибку выполнения JavaScript «function timeout error».
Использовать библиотеку
Многие библиотеки включают в себя встроенные функции, необходимые для решения проблемы с this. Например, метод jQuery.proxy(). Он берет функцию и возвращает новую, в которой всегда будет использовать определенный контекст. В нашем случае, контекстом будет:
setTimeout($.proxy(person.introduce, person), 50);
Посмотреть демо
Отключение таймера
Возвращенное значение setTimeout представляет собой числовой id, который можно использовать для отключения таймера при помощи функции clearTimeout():
var timer = setTimeout(myFunction, 3000); clearTimeout(timer);
Давайте посмотрим на нее в действии. В следующем примере, если кликнуть по кнопке «Start countdown», начнется обратный отсчет. После того, как он завершится, котята получат свое. Но если нажать кнопку «Stop countdown», таймер JavaScript timeout будет остановлен и сброшен.
Посмотреть пример
Подитожим
- Методы setInterval(func, delay, …args) и setTimeout(func, delay, …args) позволяют выполнять func только один раз или регулярно после задержки delay, заданной в мс.
- Для отмены выполнения нужно вызвать clearInterval/clearTimeout со значением, возвращающим методы setInterval/setTimeout.
- Вложенный вызов setTimeout – более гибкая альтернатива setInterval. Кроме того он позволяет точнее задать интервал между выполнениями.
- Планирование с нулевой задержкой setTimeout(func,0) или, что то же самое, setTimeout(func) применяется для вызовов, которые должны быть выполнены как можно быстрее, после завершения исполнения текущего кода.
Браузер ограничивает 4 мс минимальную задержку между 5 и более вложенными вызовами setTimeout, а также для setInterval, начиная с 5 вызова. Учтите, что все методы планирования не могут гарантировать точной задержки. Например, таймер может замедляться по следующим причинам:
- Перегружен процессор.
- Работа ноутбука от аккумулятора.
- Вкладка веб-браузера в фоновом режиме.
Эти факторы могут увеличивать минимальный интервал срабатывания таймера до 300 или 1000 мс в зависимости от настроек производительности ОС и используемого браузера.
Главный поток
В каждом окне выполняется только один главный поток, который занимается выполнением JavaScript, отрисовкой и работой с DOM.
Он выполняет команды последовательно, может делать только одно дело одновременно и блокируется при выводе модальных окон, таких как .
Дополнительные потоки тоже есть
Есть и другие, служебные потоки, например, для сетевых коммуникаций.
Поэтому скачивание файлов может продолжаться пока главный поток ждёт реакции на . Но управлять служебными потоками мы не можем.
Web Workers
Существует спецификация Web Workers, которая позволяет запускать дополнительные JavaScript-процессы(workers).
Они могут обмениваться сообщениями с главным процессом, но у них свои переменные, и работают они также сами по себе.
Такие дополнительные процессы не имеют доступа к DOM, поэтому они полезны, преимущественно, при вычислениях, чтобы загрузить несколько ядер/процессоров одновременно.
setTimeout()
Эту функцию вы видели выше, а сейчас узнаете про неё ещё детальнее. Она используется в основном в тех случаях, если вы хотите запустить вашу функцию через конкретное количество миллисекунд после вызова самого . Синтаксис для этого метода такой:
setTimeout ( expression, timeout );
Тут в JavaScript коде запустится по прошествии миллисекунд, указанных в аргументе .
также возвращает для тайм-аута, чтобы его можно было отследить. Но в основном оно используется для метода , который останавливает выполнение отложенной функции. В качестве аргумента тут нужно вставить (название) функции.
Вот ещё один пример:
<input type="button" name="sayHello" value="Wait for my Hello!"onclick="setTimeout('alert(\'Hello!\')', 4000)"/>
При нажатии на кнопку запускается метод. Выражение, запуск которого по вашему предусмотрению должен произойти с задержкой в 4000ms или 4 секунды, уже передано.
Тут стоит обратить внимание на то, что не останавливает выполнение дальнейшего скрипта во время периода тайм-аута. Он просто откладывает выполнение указанного блока кода на заложенное количество времени
После вызова функции , скрипт продолжит выполняться обычным образом, с таймером на фоне.
То, что выше — это простой пример со всем кодом для alert бокса в вызове. На практике же, вы будете вызывать функции внутри таймеров гораздо чаще. Следующий пример даст вам лучшее понимание о вызове функций с помощью .
Для примера, код ниже, вызывает через одну секунду:
function sayHello() {alert('Hello');}setTimeout(sayHello, 1000);
Вы можете также передавать аргументы вместе с функцией, например, как тут:
function sayHello(message, person) {alert( message + ', '+ person );}setTimeout(sayHello, 1000, "Hi", "Monica"); // Hi, Monica
Как вы видите, для сначала передаётся функция аргумент, затем время задержки и уже только потом аргументы для функции аргумента(пардон за каламбур).
Если первый аргумент это строка, то JavaScript может создать из неё функцию. Так что вот это тоже сработает:
setTimeout("alert('Hello')", 1000);
Но применение такого метода не рекомендуется, лучше используйте функции, как тут:
setTimeout(() => alert('Hello'), 1000);
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
중첩 setTimeout
무언가를 일정 간격을 두고 실행하는 방법에는 크게 2가지가 있습니다.
하나는 을 이용하는 방법이고, 다른 하나는 아래 예시와 같이 중첩 을 이용하는 방법입니다.
다섯 번째 줄의 은 로 표시한 줄의 실행이 종료되면 다음 호출을 스케줄링합니다.
중첩 을 이용하는 방법은 을 사용하는 방법보다 유연합니다. 호출 결과에 따라 다음 호출을 원하는 방식으로 조정해 스케줄링 할 수 있기 때문입니다.
5초 간격으로 서버에 요청을 보내 데이터를 얻는다고 가정해 봅시다. 서버가 과부하 상태라면 요청 간격을 10초, 20초, 40초 등으로 증가시켜주는 게 좋을 겁니다.
아래는 이를 구현한 의사 코드입니다.
CPU 소모가 많은 작업을 주기적으로 실행하는 경우에도 을 재귀 실행하는 방법이 유용합니다. 작업에 걸리는 시간에 따라 다음 작업을 유동적으로 계획할 수 있기 때문입니다.
중첩 을 이용하는 방법은 지연 간격을 보장하지만 은 이를 보장하지 않습니다.
아래 두 예시를 비교해 봅시다. 첫 번째 예시에선 을 이용했습니다.
두 번째 예시에선 중첩 을 이용했습니다.
첫 번째 예시에선, 내부 스케줄러가 를 100밀리초마다 실행합니다.
그림을 보고 뭔가 알아차리셨나요?
을 사용하면 호출 사이의 지연 간격이 실제 명시한 간격(100ms)보다 짧아집니다!
이는 을 실행하는 데 ‘소모되는’ 시간도 지연 간격에 포함시키기 때문입니다. 지극히 정상적인 동작이죠.
그렇다면 을 실행하는 데 걸리는 시간이 명시한 지연 간격보다 길 때 어떤 일이 발생할까요?
이런 경우는 엔진이 의 실행이 종료될 때까지 기다려줍니다. 의 실행이 종료되면 엔진은 스케줄러를 확인하고, 지연 시간이 지났으면 다음 호출을 바로 시작합니다.
따라서 함수 호출에 걸리는 시간이 매번 밀리초보다 길면, 모든 함수가 쉼 없이 계속 연속 호출됩니다.
한편, 중첩 을 이용하면 다음과 같이 실행 흐름이 이어집니다.
중첩 을 사용하면 명시한 지연(여기서는 100ms)이 보장됩니다.
이렇게 지연 간격이 보장되는 이유는 이전 함수의 실행이 종료된 이후에 다음 함수 호출에 대한 계획이 세워지기 때문입니다.
가비지 컬렉션과 setInterval·setTimeout
이나 에 함수를 넘기면, 함수에 대한 내부 참조가 새롭게 만들어지고 이 참조 정보는 스케줄러에 저장됩니다. 따라서 해당 함수를 참조하는 것이 없어도 과 에 넘긴 함수는 가비지 컬렉션의 대상이 되지 않습니다.
의 경우는, 이 호출되기 전까지 함수에 대한 참조가 메모리에 유지됩니다.
그런데 이런 동작 방식에는 부작용이 하나 있습니다. 외부 렉시컬 환경을 참조하는 함수가 있다고 가정해 봅시다. 이 함수가 메모리에 남아있는 동안엔 외부 변수 역시 메모리에 남아있기 마련입니다. 그런데 이렇게 되면 실제 함수가 차지했어야 하는 공간보다 더 많은 메모리 공간이 사용됩니다. 이런 부작용을 방지하고 싶다면 스케줄링할 필요가 없어진 함수는 아무리 작더라도 취소하도록 합시다.



