Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 13.11.2013, 05:27
Новичок на форуме
Отправить личное сообщение для Bombus Посмотреть профиль Найти все сообщения от Bombus
 
Регистрация: 13.11.2013
Сообщений: 6

Контекст функции при вызове по таймеру
Здравствуйте. При изучении учебника по Javascript возник вопрос. В теме про таймеры есть упражнение "Вывод чисел каждые 100мс". Код решения:
function printNumbersInterval20_100() {
  var i = 1;
  var timerId = setInterval(function() {
    console.log(i);
    if (i == 20) clearInterval(timerId);
    i++;
  }, 100);
}
 
// вызов
printNumbersInterval20_100();

Не понял расклад по контексту (видимости переменных) в случае вызова setInternal() из функции (не из глобального контекста), в нашем случае printNumbersInterval20_100. Из текста статьи, цитирую: "Вызов через setTimeout не передаёт контекст this. В частности, вызов метода объекта через setTimeout сработает в глобальном контексте". Так вот если наша анонимная функция сработает через указанное время в глобальном контексте, то откуда она будет знать про переменную i, которая определена локально во внешней функции? Как я понимаю, setInternal не блокирует выполнение скрипта, в данном случае не останавливает выполнение функции printNumbersInterval20_100. Т.е.создав таймер "в отдельном потоке", функция продолжает выполнятся и в конце концов заканчивается. Тогда откуда берется сохраненное значение i?
Ответить с цитированием
  #2 (permalink)  
Старый 13.11.2013, 06:34
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 13,217

Сообщение от Bombus
Тогда откуда берется сохраненное значение i?
Так это значение передано, как и значение timerId...
Ответить с цитированием
  #3 (permalink)  
Старый 13.11.2013, 06:49
Новичок на форуме
Отправить личное сообщение для Bombus Посмотреть профиль Найти все сообщения от Bombus
 
Регистрация: 13.11.2013
Сообщений: 6

Разве передано? function(), т.е. параметры не передаются. А тело функции, имхо, будет получать значения исходя из контекста, исходя из окружения в момент выполнения, который случиться позже, когда внешняя функция printNumbersInterval20_100() уже завершиться. Да и контекст анонимной функции, согласно статье, глобальный. Где я ошибаюсь?
Ответить с цитированием
  #4 (permalink)  
Старый 13.11.2013, 06:55
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 13,217

Сообщение от Bombus
Разве передано?
Да.

Сообщение от Bombus
function(), т.е. параметры не передаются.
Для function() они глобальные...

Сообщение от Bombus
А тело функции, имхо, будет получать значения исходя из контекста, исходя из окружения в момент выполнения, который случиться позже
Дело уже сделано. И нет уже никакого "позже"...
Ответить с цитированием
  #5 (permalink)  
Старый 13.11.2013, 07:01
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 13,217

Bombus, почитай коментарии к этой статье до конца...
Ответить с цитированием
  #6 (permalink)  
Старый 13.11.2013, 07:02
Новичок на форуме
Отправить личное сообщение для Bombus Посмотреть профиль Найти все сообщения от Bombus
 
Регистрация: 13.11.2013
Сообщений: 6

Ok, а как же (цитата из учебника):
"Вызов через setTimeout не передаёт контекст this. В частности, вызов метода объекта через setTimeout сработает в глобальном контексте".
Т.е. переменные из внешней функции передаются, а контекст нет?
Ответить с цитированием
  #7 (permalink)  
Старый 13.11.2013, 07:03
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 13,217

Сообщение от Bombus
контекст this
Не стоит равнять this с "обычними" переменными...
Ответить с цитированием
  #8 (permalink)  
Старый 13.11.2013, 20:58
Новичок на форуме
Отправить личное сообщение для Bombus Посмотреть профиль Найти все сообщения от Bombus
 
Регистрация: 13.11.2013
Сообщений: 6

ksa, предложу немного измененный вариант исходного кода:
function printNumbersInterval20_100() {
  var i = 1, point = 'start';
  var timerId = setInterval(function() {
    console.log(i + ' ' + point);
    if (i == 20) clearInterval(timerId);
    i++;
  }, 100);
  point = 'finish'; 
}

В логах пишется:
1 finish
2 finish
.........
20 finish

Кажется механизм передачи переменных следующий:
1. При выполнении функции printNumbersInterval20_100() создается анонимная функция, которая привязывается к таймеру. Также ей передается ссылка на VariableEnviroment (а может и на LexicalEnvironment) от вызывающей функции, но все-же это не передача параметров функции.
2. printNumbersInterval20_100() уже может выполнится полностью, когда таймер сработает первый раз, но завершение функции будет означать лишь остановку действий внешней функции, а VariableEnviroment останется висеть в памяти. Примерно как это происходит с замыканиями - внешняя функция вроде завершена, но список переменных из памяти не выгружается пока на них будут ссылаться другие функции.
3. Анонимная функция при срабатывания таймера берет значения из переданного объекта VariableEnviroment. Т.е. ей не передается снимок переменных в момент создания анонимной функции из printNumbersInterval20_100(), а именно переменные в функцию попадают по ссылке в момент сработки таймера.
Еще один вывод: если таймеров создается много, то необходимо их после выполнения(!) чистить "ручками", а не оставлять на без присмотра, иначе будет копиться мусор и могут появиться тормоза. Где-то на форуме видел рекомендации про чистку при создании тысяч таймеров в обязательном порядке, иначе система может тормозить.
Если я не прав, прошу поправить.
Ответить с цитированием
  #9 (permalink)  
Старый 13.11.2013, 21:27
Аватар для BETEPAH
Профессор
Отправить личное сообщение для BETEPAH Посмотреть профиль Найти все сообщения от BETEPAH
 
Регистрация: 23.06.2011
Сообщений: 1,165

Bombus,
У вас 6я строка отрабатывает каждые 0.1 секунды, а 8я еще ДО того момента, когда закончится первый интервал. Может так понятнее будет:
function printNumbersInterval20_100() {
  var i = 1, point = 'start';
  var timerId = setInterval(function() {
    console.log(i + ' ' + point);
    if (i == 20) clearInterval(timerId);
    i++;
	point = (point =='finish') ? 'start' : 'finish';
  }, 100);
}
printNumbersInterval20_100();
Ответить с цитированием
  #10 (permalink)  
Старый 13.11.2013, 22:19
Новичок на форуме
Отправить личное сообщение для Bombus Посмотреть профиль Найти все сообщения от Bombus
 
Регистрация: 13.11.2013
Сообщений: 6

BETEPAH,
Что-то не понял, что вы хотели сказать. Т.е. подтверждаете тот механизм передачи значения переменных через VariablrEnviroment?
Мне показалось что в вашем коде пропущена строка
point = 'finish';
в конце функции printNumbersInterval20_100, т.к. в логах занчения point чередуются между 'start' и 'finish'.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
При вычислении значения функции страница зависает Nellie Ваши сайты и скрипты 1 08.04.2013 21:04
хитросплетения Global,контекст,this,Reference kefi Общие вопросы Javascript 109 20.11.2009 22:34
Замыкание - это... Zeroglif Общие вопросы Javascript 11 06.03.2009 21:04
тест magistr_bender Оффтопик 44 25.10.2008 18:28
не работают функции при их вызове(не отображаются кнопки) badfilin Общие вопросы Javascript 0 08.04.2008 19:18