Вы думаете, setTimeout останавливает работу Javascript? Нет, таймеры в Javascript работают по-другому: они откладывают на определённое время только одну задачу. | |
учебник HTML скачать
| Таймеры в Javascript (setInterval, setTimeout)В программировании на скриптовых языках периодически возникает необходимость создать паузу – приостановить выполнение программы на некоторое время, а потом продолжить работу. Например, в сценариях VBS и PHP возможны такие методы: VBS: wscript.sleep 1500 (остановка на 1.5 секунды) PHP: sleep(10); (остановка на 10 секунд) Во время подобных пауз исполняющая система (PHP или VBS) ничего не делает. Разработчик, попытавшись интуитивно использовать нечто подобное в Javascript, будет неприятно удивлён. Типичная ошибка при попытке создать паузу в Javascript выглядит так:
Вы думаете, что, когда при прохождении цикла очередь дойдёт до рисования очередной цифры, ваш setTimeout честно остановит работу Javascript, подождёт 0.9 сек., добавит в конец поля ввода нужную цифру и потом продолжит работу. Но на самом деле это не так: setInterval и setTimeout в Javascript откладывают выполнение только того действия (или функции), которое указано в скобках. В нашем примере произойдёт следующее:
Немедленно означает, например, 1 мс (то есть несоизмеримо мало, по сравнению с 900 мс): цикл прозведёт свою работу практически мгновенно, создав несколько отложенных задач от одной и той же точки времени. Это значит, все отложенные задачи по "рисованию" будут выполнены практически в одно и то же время, без пауз между добавлением новых цифр. Цикл запускается; всё замирает на 0.9 с; и ширрр – все цифры выстреливаются в ряд одна за другой. А как в подобном случае правильно применить setTimeout? Это сложно. Придётся вызывать функцию рекурсивно (изнутри функции ту же самую функцию), а чтобы этот процесс не был бесконечным, задать условие остановки (например, величину печатаемого числа): И ещё переменную i придётся инициализировать вне функции – например, так:
Вот теперь всё работает, как надо (мы уменьшили время задержки с 0.9 с до 0.4 с). Но для подобных задач логичнее всё-таки применять не setTimeout а setInterval (хотя при этом понадобится две функции):
Особенность метода Javascirpt setInterval в том, что он не проходит «сам собой», его надо останавливать специальным методом clearInterval. А чтобы было понятно, что именно останавливать, задаче по отложенному действию присваивается специальнй идентификатор – таймер: window.timer1 = window.setInterval(...). Идентификаторы можно присваивать так же и задачам, создаваемым методом setTimeout. Все идентификаторы таймеров должны отличаться друг от друга (быть уникальными в пределах текущего окна браузера). Тогда можно создать в окне несколько разных задач, использующих отложенные действия, и эти задачи будут выполняться параллельно (вроде как одновременно, если у компьютера хватает ресурсов), что в принципе невозможно в PHP или VBS. Вот пример страницы с несколькими Javascript-таймерами, работающими одновременно: setinterval.htm (Javascript-функции в файле setinterval.js). Работу всех таймеров страницы (кроме меню) можно остановить клавишей Esc. Все таймеры примеров опираются на «естественный» (а не абстрактное i++) отсчёт – времени или расстояния. Все «часы» специально рассинхронизированы (для наглядности). Таймеры, зависящие от расстояния, используются в «индикаторе» и в выпадающем («выезжающем») меню. Выпадающее менюНаше выезжающее меню – реально выезжающее (из-под «шапки»): между элементами специально оставлены зазоры, чтобы видеть, как оно выезжает. Неожиданно оказалось, что мы не можем сделать одинаково плавный выезд для списков разной длины – вероятно, из-за низкой производительности компьютера (AMD Athlon 999 МГц). Достаточно очевидно, что для красоты и гармонии нужно, чтобы списки разных пунктов меню выпадали за одно и то же время. То есть более длинные списки должны выпадать с более высокой скоростью, более короткие – с меньшей скоростью. Казалось бы, это можно реализовать так:
По этой логике, если выпадающий список имеет высоту 200 px, мы должны двигать его вниз по одному пикселу за 1 мс. Но такая скорость на нашем компьютере не прокатывает – браузер просто не успевает отрисовывать новое положение списка за одну миллисекунду. Да. Javascript считать успевает (что там считать-то?), а браузер (Firefox) отображать не успевает. Типичная ситуация для веб. Поэтому более-менее уровнять время выезжания меню можно только с помощью костылей, и ещё неясно, как это будет работать на более быстром компьютере. Но мы ведь должны рассчитывать на самый медленный? Алгоритм (без учёта быстродействия компьютера) получается примерно такой:
Вот теперь списки более-менее выезжают. За более-менее похожее время. На странице setinterval.htm. А вот и Брю-ус: Сама функция, выдвигающая вложенные списки из меню, как видим, очень проста. Осталось только запустить её примерно такой строкой: Ну, а перед запуском только вычислить все эти maxtop и offset, а также поместить список в положение mintop. Чем и занимается «предварительная» функция slide() размером в 40 строк. А всё вместе - в файле setinterval.js. Да, и эта хрень ни хрена не будет работать без подключенного файла стилей menuroll.css. D.M., admin Добавить комментарий: |