Задача
Порой, для отслеживания каких-либо операций или событий по таймауту (например, содержимого тектового поля, которое, как известно, можно изменить в обход нативных обработчиков событий), применяют рекурсивные функции, вызываемые с помощью setTimeout (setInterval не подходит, так как технология использования setTimeout гарантированно позволяет выполнять определенные действия через равные промежутки времени, в то время, как setInterval не гарантирует равную величину временных промежутков. Подробнее.)Пример такой функции:
(function () {Явный недостаток такого подхода - это невозможность остановить выполнение кода. В данном примере в лог будут сыпаться рандомные числа каждые 3 секунды.
var test = arguments.callee;
var t = setTimeout(function () {
console.log(Math.random());
test()
}, 3000)
})();
Как все же управлять жизнью таких конструкций?
Варианты решений.
1.Деанонимизация
Самая простая идея - не делать рекурсивную функцию анонимной:// Сперва объявляем функцию
var test = function () {
var t = setTimeout(function () {
console.log(Math.random());
test();
}, 3000)
};
// Затем, запускаем
(function () {
test();
})();
Теперь, для остановки просто удаляем нашу функцию:
delete test;
2. Замыкание или инкапсуляция
Основная идея состоит в том, чтобы в выполняемой функции отслеживать состояние некоторой переменной, глобальной по отношению к рекурсивной функции, доступной через замыкание, и, в зависимости от ее состояния, выполнять очередную итерацию или нет. Аналогично можно использовать свойства объекта, если рекурсивная функция является его методом.
var flag = true;
(function () {
if(flag) {
var test = arguments.callee;
var t = setTimeout(function () {
console.log(Math.random());
test()
}, 3000);
}
})();
3. clearTimeout
Идея состоит в том, чтобы передавать значение, возвращаемое setTimeout глобальной в отношении рекурсивной функции переменной (или свойству объекта). И в нужный момент передавать значение этой переменной в качестве аргумента clearTimeout:
// Объявляем переменную для таймаутаvar t;(function () {var test = arguments.callee;t = setTimeout(function () {console.log(Math.random());test()}, 3000)})();
Останавливаем выполнение:
clearTimeout(t);
Итог.
Конечно, все зависит от конечной реализации, но в приведенных примерах, третий подход гарантированно завершает выполнение кода в момент вызова clearTimeout, в то время, как остальные подходы допускают завершение кода, в теле setTimeout.
Комментариев нет:
Отправить комментарий