Повторювати дії через заданий інтервал часу JavaScript. SetTimeOut та SetInterval, що краще використовувати в JavaScript? Мінімальна затримка таймера

  • Від:
  • Registered: 2014.07.08
  • Posts: 3,896
  • Порівняти: 497
Topic: SetTimeOut та SetInterval, що краще використовувати в JavaScript?

Для багаторазового запуску коду через рівні проміжки часу призначена функція setInterval. Тим не менш вона має ряд мінусів, в основному це різна поведінка в різних браузерах.

Перша відмінність полягає у різниці моменту встановлення таймера для наступного запуску. Створимо невеликий тест: відмірятимемо кількість часу, що минув з початку виконання попереднього запуску та з його закінчення.

var d1 = New Date(), d2 = New Date(); setInterval(function() ( var d = New Date(); document.body.innerHTML += (d - d1) + " " + (d - d2) + "
// Ставимо мітку на початку функції d1 = new Date(); while (new Date() - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

Висновок буде інформативним, починаючи з другого рядка.

У Firefox, Opera, Safari і Chrome ситуація буде схожа: перше число приблизно дорівнює 1000, друге - на 200 менше. Відмінність буде лише у розкиді значень. Найменший розкид у Chrome та Opera.

2 Reply by PunBB.
  • Від: Moscow, Sovkhoznay 3, apt. 98
  • Registered: 2014.07.08
  • Posts: 3,896
  • Порівняти: 497

Ще одна відмінність менш помітна і більш відтворювана, але іноді здатна завдати багато турбот, - це стійкість до зміни системного часу. Якщо запустити наступний тест

setInterval(function() ( document.body.innerHTML = Math.random(); ), 500);

І після запуску перевести системний час на хвилину тому, то в браузерах Firefox і Safari зміна чисел припиниться, а за хвилину запуститься знову. Звичайно, ручне переведення системного часу вкрай рідкісна ситуація, але на багатьох системах налаштована автоматична синхронізація часу з серверами в інтернеті, тому в деяких ситуаціях не можна скидати з рахунків цей фактор.

Ще один маленький мінус функції setInterval - щоб була можливість зупинити її дію, необхідно десь запам'ятовувати її ідентифікатор, що завжди зручно.

3 Reply by PunBB
  • Від: Moscow, Sovkhoznay 3, apt. 98
  • Registered: 2014.07.08
  • Posts: 3,896
  • Порівняти: 497
Re: SetTimeOut та SetInterval, що краще використовувати в JavaScript?

Щоб позбутися перерахованих недоліків setInterval, можна використовувати багаторазовий setTimeout.

Важлива альтернатива setInterval – рекурсивний setTimeout:

/** замість: var timerId = setInterval(function() ( alert("тік"); ), 2000); */ var timerId = setTimeout(function tick() ( alert("тік"); timerId = setTimeout(tick, 2000); ), 2000);

У коді вище наступне виконання планується одразу після закінчення попереднього.

Рекурсивний setTimeout – більш гнучкий метод таймінгу, ніж setInterval, оскільки час до наступного виконання можна запланувати по-різному, залежно від поточного результату.

Наприклад, у нас є сервіс, який раз на 5 секунд опитує сервер на предмет нових даних. Якщо сервер перевантажений, можна збільшувати інтервал опитування до 10, 20, 60 секунд… А потім повернути назад, коли все нормалізується.

Якщо у нас регулярно проходять вантажуючі процесор завдання, то ми можемо оцінювати час, витрачений на їх виконання, і планувати наступний запуск раніше чи пізніше.

4 Reply by PunBB
  • Від: Moscow, Sovkhoznay 3, apt. 98
  • Registered: 2014.07.08
  • Posts: 3,896
  • Порівняти: 497
Re: SetTimeOut та SetInterval, що краще використовувати в JavaScript?

Рекурсивний setTimeout гарантує паузу між викликами, setInterval – ні.

Давайте порівняємо два коди. Перший використовує setInterval:

var i = 1; setInterval(function() ( func(i); ), 100);

Другий використовує рекурсивний setTimeout:

var i = 1; setTimeout(function run() ( func(i); setTimeout(run, 100); ), 100);

При setInterval внутрішній таймер спрацьовуватиме чітко кожні 100 мс і викликатиме func(i):

Реальна пауза між викликами func при setInterval менша, ніж зазначена в коді!

Це природно, адже час роботи функції не враховується, воно «з'їдає» частину інтервалу.

Можливо і таке, що func виявилася складнішою, ніж ми розраховували і виконувалася довше, ніж 100 мс.

У цьому випадку інтерпретатор чекатиме, поки функція завершиться, потім перевірить таймер і, якщо час виклику setInterval вже підійшов (або минув), то наступний виклик відбудеться відразу.

Якщо функція і виконується довше, ніж пауза setInterval, то виклики відбуватимуться взагалі без перерви.

5 Reply by sempai
  • Від: Jerusalem
  • Registered: 2015.06.02
  • Posts: 958
  • Опис: 274
Re: SetTimeOut та SetInterval, що краще використовувати в JavaScript?

Все залежить від поставленого завдання. Спочатку SetTimeOut служить для одноразового запуску таймера, а SetInterval - для запуску циклу. Але і ту і іншу функцію можна використовувати для циклічної прогонки скриптів, якщо, наприклад, запустити рекурсивно у функції SetTimeOut, то вона діятиме практичний аналогічно SetInterval.

Мінус SetInterval на сьогоднішній момент, що він не враховує час на виконання самого скрипта (функції), і якщо ви використовуєте його для важких запитів, то час інтервалу істотно скоротитися, та й у різних браузерах може відрізнятися.

Але знову ж таки повторюся, якщо функція або запит мінімізовані, то кінцевий користувач навряд чи відчує різницю.
Тому що використовувати, вирішує кожен сам

JavaScript timeout є нативною javascript-функцією , яка виконує фрагмент коду після встановленої тимчасової затримки (у мілісекундах ). Це може стати в нагоді, коли потрібно вивести вікно, що спливає після того, як користувач провів деякий час на вашій сторінці. Або потрібно, щоб ефект при наведенні курсору на елемент запускався лише через якийсь час. Таким чином, можна уникнути ненавмисного запуску ефекту, якщо користувач навів курсор випадково.

Простий приклад setTimeout

Щоб продемонструвати дію цієї функції, пропоную подивитись наступне демо, у якому спливаюче вікно з'являється через дві секунди після натискання кнопки.

Подивитись демо

Синтаксис

У документації MDN наведено наступний синтаксис для setTimeout:

var timeoutID = window.setTimeout(func, ); var timeoutID = window.setTimeout(code, );

  • timeoutID – числовий id , який можна використовувати разом із clearTimeout() для відключення таймера;
  • func – функція, яка має бути виконана;
  • code (в альтернативному синтаксисі) – рядок коду, який потрібно виконати;
  • delay – тривалість затримки у мілісекундах, після якої буде запущено функцію. За промовчанням встановлено значення 0.
setTimeout vs window.setTimeout

У наведеному вище синтаксисі використовується window.setTimeout. Чому?

Насправді setTimeout і window.setTimeout – це практично одна і та ж функція. Єдина різниця полягає в тому, що в другому виразі ми використовуємо метод setTimeout як властивість глобального об'єкта window.

Особисто я вважаю, що це дуже ускладнює код. Якби ми визначили альтернативний метод JavaScript timeout, який може бути знайдений і повернутий у пріоритетному порядку, то зіткнулися б із ще більшими проблемами.

У цьому посібнику я не хочу зв'язуватися з об'єктом window, але в цілому ви самі вирішуєте, який синтаксис варто використовувати.

Приклади використання

Це може бути назва функції:

function explode()( alert("Boom!"); ) setTimeout(explode, 2000);

Змінна, яка звертається до функції:

var explode = function()( alert("Boom!"); ); setTimeout(explode, 2000);

Або ж анонімна функція:

setTimeout(function()( alert("Boom!"); ), 2000);

  • Такий код погано сприймається, а отже його складно буде модернізувати або налагодити;
  • Він передбачає використання методу eval(), який може стати потенційною вразливістю;
  • Цей метод працює повільніше за інших, тому що йому потрібно запускати JavaScript-інтерпретатор.

Також зауважте, що для тестування коду ми використовуємо метод alert для JavaScript timeout .

Передаємо параметри у setTimout

У першому (до того ж, кросбраузерному) варіанті ми передаємо параметри в callback-функцію, що виконується за допомогою setTimeout.

У наступному прикладі ми виділяємо випадкове вітання з масиву greetings і передаємо його як параметр функції greet() , яка виконується setTimeout із затримкою в 1 секунду:

function greet(greeting)( console.log(greeting); ) function getRandom(arr)( return arr; ) var greetings = ["Hello", "Bonjour", "Guten Tag"]; setTimeout(function()( greet(randomGreeting); ), 1000);

Подивитись демо

Альтернативний метод

У синтаксисі, наведеному на початку статті, існує ще один метод, за допомогою якого можна передати параметри в callback-функцію JavaScript timeout . Цей метод має на увазі під собою виведення всіх параметрів, що настають після затримки.

Спираючись на попередній приклад, ми отримуємо:

setTimeout(greet, 1000, randomGreeting);

Цей метод не буде працювати в IE 9 і нижче, де параметри, що передаються, розцінюються як undefined . Але для вирішення цієї проблеми на MDN є спеціальний поліфіл.

Супутні проблеми та “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.

Щоб позбавитися цієї нестиковки, можна скористатися кількома методами:

Примусово встановити значення цього

Це можна зробити за допомогою bind() – методу, який створює нову функцію, яка при виклику як значення ключа this використовує певне значення. У нашому випадку – зазначений об'єкт person. Це в результаті дає нам:

setTimeout(person.introduce.bind(person), 50);

Примітка: метод bind був представлений в ECMAScript 5 , а значить, він працюватиме тільки в сучасних браузерах. В інших при його застосуванні ви отримаєте помилку виконання JavaScript "function timeout error".

Використовувати бібліотеку

Багато бібліотек включають вбудовані функції, необхідні для вирішення проблеми з цим. Наприклад, метод jQuery.proxy(). Він бере функцію і повертає нову, у якій завжди використовуватиме певний контекст. У нашому випадку контекстом буде:

setTimeout($.proxy(person.introduce, person), 50);

Подивитись демо

Вимкнення таймера

Повернене значення setTimeout є числовим id , який можна використовувати для відключення таймера за допомогою функції clearTimeout() :

var timer = setTimeout(myFunction, 3000); clearTimeout(timer);

Погляньмо на неї в дії. У наступному прикладі, якщо натиснути на кнопку «Start countdown», почнеться зворотний відлік. Після того, як він завершиться, кошенята отримають своє. Але якщо натиснути кнопку "Stop countdown", таймер JavaScript timeout буде зупинений і скинутий.

Подивитися приклад

Підведемо підсумки

setTimeout - асинхронна функція, а це означає, що отримане звернення до цієї функції потрапляє в чергу, і буде виконано тільки після того, як завершаться решта дій у стеку. Вона не може працювати одночасно з іншими функціями чи окремим потоком.

Джерело: http://learn.javascript.ru/settimeout-setinterval

Майже всі реалізації JavaScript мають внутрішній таймер-планувальник, який дає змогу задавати виклик функції через заданий період часу.

Зокрема, ця можливість підтримується у браузерах та сервері Node.JS.

setTimeout

Синтаксис:

var timerId = setTimeout(func/code, delay[, arg1, arg2...])

Параметри:

  • func/code
    • Функція або рядок коду для виконання.
    • Рядок підтримується для сумісності, використовувати її не рекомендується.
  • delay
    • Затримка в мілісекундах, 1000 мілісекунд дорівнюють 1 секунді.
  • arg1, arg2…
    • Аргументи, які необхідно передати функції. Не підтримуються в IE9-.
    • Виконання функції відбудеться через час, вказаний у параметрі delay .

Наприклад, наступний код викликає alert("Привіт") за одну секунду:

function func () ( alert("Привіт"); ) setTimeout(func, 1000);

Якщо перший аргумент є рядком, інтерпретатор створює анонімну функцію з цього рядка.

Тобто такий запис працює так само:

SetTimeout("alert("Привіт")", 1000);

Замість них використовуйте анонімні функції:

SetTimeout(function () (alert("Привіт")), 1000);

Параметри для функції та контекст

У всіх сучасних браузерах, з урахуванням IE10, setTimeout дозволяє вказати параметри функції.

Приклад нижче виведе "Привіт, я Вася" скрізь, крім IE9-:

function sayHi (who) (alert("Привіт, я" + who); ) setTimeout(sayHi, 1000, "Вася");

…Однак у більшості випадків нам потрібна підтримка старого IE, а він не дозволяє вказувати аргументи. Тому, щоб їх передати, обертають виклик в анонімну функцію:

function sayHi (who) (alert("Привіт, я" + who);) setTimeout(function() (sayHi("Вася")), 1000);

Виклик через setTimeout не передає контекст this.

Зокрема, виклик методу об'єкта через setTimeout спрацює у глобальному контексті. Це може призвести до неправильних результатів.

Наприклад, викличемо user.sayHi() за одну секунду:

function User (id) function () ( alert(this .id); ); ) var user = new User(12345); setTimeout(user.sayHi, 1000); // очікується 12345, але виведе "undefined"

Оскільки setTimeout запустить функцію user.sayHi у глобальному контексті, вона не матиме доступу до об'єкта через це .

Інакше кажучи, ці два виклики setTimeout роблять те саме:

// (1) один рядок setTimeout(user.sayHi, 1000); // (2) те саме в два рядки var func = user.sayHi; setTimeout(func, 1000);

На щастя, ця проблема також легко вирішується створенням проміжної функції:

function User (id) ( this .id = id; this .sayHi = function () ( alert(this .id); ); ) var user = new User(12345 ); setTimeout(function () (user.sayHi();), 1000);

Функція-обгортка використовується, щоб крос-браузерно передати аргументи та зберегти контекст виконання.

Скасування виконання

Функція setTimeout повертає ідентифікатор timerId , який можна використовувати для скасування дії.

Синтаксис:

ClearTimeout(timerId)

У наступному прикладі ми ставимо тайм-аут, а потім видаляємо (передумали). В результаті нічого не відбувається.

var timerId = setTimeout(function () (alert(1)), 1000); clearTimeout(timerId); setInterval

Метод setInterval має синтаксис, аналогічний setTimeout.

var timerId = setInterval(func/code, delay[, arg1, arg2...])

Сенс аргументів — той самий. Але, на відміну setTimeout , він запускає виконання функції неодноразово, а регулярно повторює її через зазначений інтервал часу. Зупинити виконання можна викликом:

ClearInterval(timerId)

Наступний приклад при запуску буде виводити повідомлення кожні дві секунди, доки ви не натиснете на кнопку «Стоп»:

var i = 1; var timer = setInterval(function () (alert(i++)), 2000); Черга та накладення викликів у setInterval

Виклик setInterval (функція, затримка) ставить функцію виконання через зазначений інтервал часу. Але тут є тонкість.

Насправді пауза між викликами менша, ніж зазначений інтервал.

Наприклад, візьмемо setInterval(function() ( func(i++) ), 100) . Вона виконує func кожні 100 мс, щоразу збільшуючи значення лічильника.

На малюнку нижче, червоний блок - це час виконання func. Час між блоком – це час між запусками функції, і він менший, ніж встановлена ​​затримка!

Тобто, браузер ініціює запуск функції акуратно кожні 100мс без урахування часу виконання самої функції.

Буває, що виконання функції займає більше часу, аніж затримка. Наприклад, функція складна, а затримка невелика. Або функція містить оператори alert/confirm/prompt, які блокують потік виконання. І тут починаються цікаві речі.

Якщо запуск функції неможливий, тому що браузер зайнятий, вона стає в чергу і виконається, як тільки браузер звільниться.

Зображення нижче ілюструє те, що відбувається для функції, яка довго виконується.

Виклик функції, ініційований setInterval , додається в чергу і негайно відбувається, коли це стає можливим:

Другий запуск функції відбувається відразу після закінчення першого:

Більше одного разу на чергу виконання не ставиться.

Якщо виконання функції займає більше часу, ніж кілька запланованих виконань, то в черзі вона все одно стоятиме один раз. Тож «накопичення» запусків не відбувається.

На зображенні нижче setInterval намагається виконати функцію 200 мс і ставить виклик у чергу. У 300 мс і 400 мс таймер прокидається знову, але нічого не проходить.

Виклик setInterval (функція, затримка) не гарантує реальної затримки виконання.

Бувають випадки, коли реальна затримка більша або менша від заданої. Взагалі не факт, що буде хоч якась затримка.

Повторення вкладеного setTimeout

У випадках, коли потрібне не просто регулярне повторення, а обов'язкова затримка між запусками, використовується повторне встановлення setTimeout при кожному виконанні функції.

Нижче приклад, який видає alert з інтервалами 2 секунди між ними.

var i = 1; var timer = setTimeout(function run () (alert(i++); timer = setTimeout(run, 2000); ), 2000);

На часовій лінії виконання будуть фіксовані затримки між запусками. Ілюстрація для затримки 100мс:

Мінімальна затримка таймера

Браузерний таймер має мінімальну можливу затримку. Вона змінюється приблизно від нуля до 4мс в сучасних браузерах. У старіших вона може бути більшою і досягати 15мс.

За стандартом мінімальна затримка становить 4мс. Тому немає різниці між setTimeout(..,1) і setTimeout(..,4) .

У поведінці setTimeout і setInterval з нульовою затримкою є браузерні особливості.

  • Opera, setTimeout(.., 0) — те саме, що setTimeout(.., 4) . Воно виконується рідше, ніж setTimeout(.. ,2). Це особливість цього браузера.
  • В Internet Explorer нульова затримка setInterval(.., 0) не спрацює. Це стосується саме setInterval, тобто. setTimeout(.., 0) працює нормально.
  • Реальна частота спрацьовування

    Спрацьовування може бути набагато рідше У ряді випадків затримка може бути не 4мс, а 30мс або навіть 1000мс.

    Більшість браузерів (десктопних в першу чергу) продовжують виконувати setTimeout / setInterval навіть якщо вкладка неактивна. При цьому ряд з них (Chrome, FF, IE10) знижують мінімальну частоту таймера до 1 разу в секунду. Виходить, що у «фоновій» вкладці спрацьовуватиме таймер, але рідко.

    При роботі від батареї, в ноутбуці браузери теж можуть знижувати частоту, щоб рідше виконувати код і заощаджувати заряд батареї. Особливо цим відомий IE. Зниження може досягати кількох разів залежно від налаштувань. При надмірному завантаженні процесора JavaScript може не встигати вчасно обробляти таймери. При цьому деякі запуски setInterval будуть пропущені.

    Висновок: на частоту 4мс варто орієнтуватись, але не варто розраховувати.

    Виведення інтервалів у консоль Код, який вважає інтервали часу між викликами, виглядає приблизно так:

    var timeMark = New Date; setTimeout(function go() ( var diff = new Date - timeMark; // вивести чергову затримку в консоль замість сторінки console .log(diff); // запам'ятаємо час у самому кінці, // щоб виміряти затримку саме між викликами timeMark = new Date;setTimeout(go, 100);), 100); Трюк setTimeout(func, 0)

    Цей трюк гідний увійти до анналів JavaScript-хаків.

    Функцію обертають setTimeout(func, 0) , якщо хочуть запустити її після закінчення поточного скрипта.

    Справа в тому, що setTimeout ніколи не виконує функції відразу. Він лише планує її виконання. Але інтерпретатор JavaScript почне виконувати заплановані функції лише після виконання поточного сценарію.

    За стандартом, setTimeout у жодному разі не може виконати функцію із затримкою 0. Як ми говорили раніше, зазвичай затримка становитиме 4мс. Але головне тут саме те, що виконання у будь-якому випадку буде після виконання поточного коду.

    Наприклад:

    var result; function showResult () ( alert(result); ) setTimeout(showResult, 0 ); result = 2 * 2; // виведе 4 Разом

    Методи setInterval(func, delay) та setTimeout(func, delay) дозволяють запускати func регулярно/один раз через delay мілісекунд.

    Обидва методи повертають ідентифікатор таймера. Його використовують для зупинки виконання викликом clearInterval/clearTimeout.

    | | setInterval | setTimeout | || ----------- | ---------- | | Таймінг | Іде виклик строго за таймером. Якщо інтерпретатор зайнятий, один виклик стає в чергу. Час виконання функції не враховується, тому проміжок часу від закінчення одного запуску до початку іншого може бути різним. | Рекурсивний виклик setTimeout використовується замість setInterval там, де потрібна фіксована пауза між виконаннями. | | Затримка Мінімальна затримка: 4мс. | Мінімальна затримка: 4мс. | | браузерні особливості | У IE не працює затримка 0. У Opera нульова затримка еквівалентна 4мс, решта затримок обробляються точно, у тому числі нестандартні 1мс, 2мс і 3мс. |

    SetInterval() метод, розташований на window and worker interfaces, repeatedly calls a function or executes a code snippet, with fixed time delay between each call. Це повертається в інтервал ID, який необов'язково identifies the interval, так що можна перейти до його терміну за допомогою callinterval() . Цей метод визначається за допомогою WindowsOrWorkerGlobalScope mixin.

    Syntax var intervalID = scope.setInterval( func, delay, [arg1, arg2, ...]); var intervalID = scope.setInterval( code, delay); Параметри func A function для виконання every delay milliseconds. Ця функція не повторюється будь-якою думкою, а не відновлене значення є виявленою. код За допомогою опційної syntax можна включити string instead of function, який є складним і виконаним кожним рівнем мільйонівкон. Цей syntax is not recommended for the same reasons that make using eval() a security risk. delay The time, в milliseconds (тисячіі з двох), the timer should delay in between executions of the specified function or code. Натисніть на деталі на визначених рівнях delay values. arg1, ..., argN Optional Additional arguments which are passed through to the function specified by func once the timer expires.

    Note : Відображення додаткових arguments до setInterval() в першій syntaxі не працює в Internet Explorer 9 і earlier. Якщо ви намагаєтеся надати цю функціональність на тому, що браузер, ви повинні використовувати polyfill (see the section).

    Return value

    Відновлений intervalID є numerical, non-zero value which identifies the timer created by the call to setInterval() ; this value can be passed to to cancel the timeout.

    Це може бути ефективним для того, щоб налаштувати, що setInterval() і setTimeout() share the sam pool of IDs, and clearInterval() and clearTimeout() can technically be used interchangeably. Для clarity, however, ви повинні намагатися до будь-якого матчу ним до avoid confusion коли maintaining ваш код.

    Note : The delay argument is converted to a signed 32-bit integer. Це ефективні терміни складає до 2147483647 ms, тому що він відповідає як ідентифікатор в IDL.

    Examples Example 1: Basic syntax

    Наступні приклади демонструють setInterval() "s basic syntax.

    Var intervalID = window.setInterval(myCallback, 500, "Parameter 1", "Parameter 2"); function myCallback(a, b) ( // Your code here // Parameters are purely optional. console.log(a); console.log(b); )

    Example 2: Alternating two colors

    Наступні приклади повідомлень про flashtext() функцію once second until Stop button is pressed.

    setInterval/clearInterval example var nIntervId; function changeColor() ( nIntervId = setInterval(flashText, 1000); ) function flashText() ( var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "red" ? " blue" : "red"; // oElem.style.color == "red" ?

    Hello World

    Stop

    Example 3: Typewriter simulation

    Наступні приклади simulates typewriter by clearing and then slowly typing content into NodeList that matches a specified group of selectors.

    JavaScript Typewriter - MDN Example function Typewriter (sSelector, nRate) ( function clean() ( clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; ) , bEraseAndStop) ( if (!oSheet.hasOwnProperty("parts") || aMap.length< nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap < oSheet.parts.length) { oRel = oSheet.parts]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets, 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts); this.parts = new Sheet(this.parts); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = , aMap = ; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems)); /* Uncomment the following line if you have previously hidden your elements via CSS: */ // aItems.style.visibility = "visible"; } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets, 0, false)); clean(); }; } /* usage: */ var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */ var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */ // oTWExample2.rate = 150; onload = function () { oTWExample1.play(); oTWExample2.play(); }; span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline; } #info { width: 180px; height: 150px; float: right; background-color: #eeeeff; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px; /* visibility: hidden; */ }

    CopyLeft 2012 by Mozilla Developer Network

    [ Play | Pause | Terminate ]

    Vivamus blandit massa ut metus mattis у fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt. JavaScript Typewriter

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, no viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat неn ipsum.

    Phasellus ac nisl lorem:
    Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque urna vitae nibh tristique varius consequat neque luctus. Integer ornare, erat a porta tempus, velit justo fermentum elit, fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa. Praesent vitae eros erat, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.

    Duis lobortis sapien quis nisl luctus porttitor. У період semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est в quam tempor consequat. Aliquam aliquam diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, у fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.

    Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque acccsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula egestas.

    Callback arguments

    Як попередньо розглянути, браузер Internet Explorer 9 і далі не підтримує проходження argumentів до callback функцій в її setTimeout() or setInterval() . Наслідуючи IE-специфічний код, демонструють метод для перехідних цих обмежень. Для того, щоб використовувати, скориставшись наступним кодом до верхнього вікна script.

    /*\ |*| |*| IE-specific polyfill that enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax)..setInterval |*| https://сайт/User:fusionchess |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay[, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, arg1, arg2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/ if (document.all && !window.setTimeout.isPolyfill) ( var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var aArg .prototype.slice.call(arguments, 2); if (document.all && !window.setInterval.isPolyfill) ( var __nativeSI__ = window.setInterval; window.setInterval = функція (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var aArgs = Ar slice.call(arguments, 2);

    Інші можливості є для використання anonymous функцій, щоб call your callback, алеякщо це рішення є bit more expensive. Example:

    Var intervalID = setInterval(function() ( myFunc("one", "two", "three"); ), 1000); var intervalID = setInterval(function(arg1) ().bind(undefined, 10), 1000);

    Inactive tabs Requires Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2)

    Starting in Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), терміни є clamped to fire no more often than once per second in inactive tabs.

    The " this " problem

    Якщо ви проймете метод до setInterval() або будь-якої іншої функції, він є внесений з відповідним цим значенням. Цей питання є розкритим в detail в JavaScript reference .

    Explanation

    Код executed by setInterval() runs in a separate execution context than the function from which it was called. Як наслідок, це ключове слово для здійсненої функції є налаштувати на window (або Global) об'єкт, який не є тим самим, як це значення для функції, що називається setTimeout . Натисніть на наступному прикладі (який використовує setTimeout() instead of setInterval() – питання, в дійсності, є саме для всіх таймерів):

    MyArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); myArray.myMethod(); // Prints "zero,one,two" myArray.myMethod(1); // Prints "one" setTimeout(myArray.myMethod, 1000); // Prints "" after 1 second setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1,5 seconds // passing the "this" object with .call won"t work // because this will change the value of this inside setTimeout itself // while we want to change the value of this inside myArray.myMethod // в fact, він повинен бути неправильним для setTimeout code expects this to be the window object: setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PRO object" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

    Як ви можете бачити, що немає способів пройти цей об'єкт до callback функцій в союзності JavaScript.

    A possible solution

    A можливо, щоб вирішити " цей " питання є замінити два природні setTimeout() or setInterval() global functions with two non-native ones that enable their invocation через Function.prototype.call метод. The following example shows a possible replacement:

    // Дозволяє перейти до "цього" об'єкта через JavaScript timers var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback in? () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); ); window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback in () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); );

    Ці дві заміни також здатні до HTML5 стандартного проходження arbitrary arguments to callback functions timers in IE. So they can be used as non-standard-compliant polyfills also. See the for a standard-compliant polyfill.

    New feature test:

    MyArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); setTimeout(alert, 1500, "Hello world!"); // Стандартний використання setTimeout і setInterval is preserved, but... setTimeout.call(myArray, myArray.myMethod, 2000); // Prints "zero,one,two" after 2 seconds setTimeout.call(myArray, myArray.myMethod, 2500, 2); // Prints "two" after 2,5 seconds

    For more complex but still modular version of it ( Daemon) JavaScript JavaScript Daemons Management . Ця більша складна версія не є тільки великою і широкою колекцією методів для Daemonконструктор. However, the Daemonконструктор йогоself is nothing but a clone of MiniDaemon with an added support for init and onstartфункції declarable протягом instantiation of the daemon. So the MiniDaemon framework remains recommended way for simple animations , because Daemonбез його колекції методів є помітно clone of it.

    minidaemon.js /*\ |*| |*| :: MiniDaemon:: |*| |*| Revision #2 - September 26, 2014.setInterval |*| https://сайт/User:fusionchess |*| https://github.com/madmurphy/minidaemon.js |*| |*| Цей framework виконаний під GNU Lesser General Public License, version 3 or later. |*| http://www.gnu.org/licenses/lgpl-3.0.html |*| \*/ function MiniDaemon (oOwner, fTask, nRate, nLen) ( if (!(this && this instanceof MiniDaemon)) ( return; ) if (arguments.length< 2) { throw new TypeError("MiniDaemon - not enough arguments"); } if (oOwner) { this.owner = oOwner; } this.task = fTask; if (isFinite(nRate) && nRate >0) ( this.rate = Math.floor(nRate); ) if (nLen > 0) ( this.length = Math.floor(nLen); ) ) MiniDaemon.prototype.owner = null; MiniDaemon.prototype.task = null; MiniDaemon.prototype.rate = 100; MiniDaemon.prototype.length = Infinity; /* These properties should be read-only */ MiniDaemon.prototype.SESSION = -1; MiniDaemon.prototype.INDEX = 0; MiniDaemon.prototype.PAUSED = true; MiniDaemon.prototype.BACKW = true; /* Global methods */ MiniDaemon.forceCall = функція (oDmn) (oDmn.INDEX += oDmn.BACKW ? -1: 1; if (oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn. .BACKW) === false || oDmn.isAtEnd()) ( oDmn.pause(); /* Instances methods */ MiniDaemon.prototype.isAtEnd = function () ( return this.BACKW ? isFinite(this.length) && this.INDEX< 1: this.INDEX + 1 >this.length; ); MiniDaemon.prototype.synchronize = function () ( if (this.PAUSED) ( return; ) clearInterval(this.SESSION); this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this); ); MiniDaemon.prototype.pause = function () ( clearInterval(this.SESSION); this.PAUSED = true; ); MiniDaemon.prototype.start = function (bReverse) ( var bBackw = Boolean(bReverse); if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) ( return; ) this.BACKW = bBackw;this.PAUSED = false;this.synchronize(); );

    MiniDaemon passes arguments до callback function. Якщо ви збираєтеся працювати на ньому з браузерами, які природно не підтримують цю особливість, використовуйте один з методів, що розкриваються.

    Syntax

    var myDaemon = New MiniDaemon( thisObject, callback[ , rate [, length]]);

    Description Usage notes

    SetInterval() функція, як правило, використовується для набору дій для функцій, які є виконаними, і так, як і animations. Ви можете відключити час, використовуючи WindowsOrWorkerGlobalScope.clearInterval() .

    If you wish to have your function називається once after the specified delay, use .

    Delay restrictions

    Це "можливе для термінів, щоб бути невтішним; що є, callback для setInterval() може в turn call setInterval() для запуску іншого терміну бігу, навіть якщо першим одним буде йти. Performance, once intervals are nested beynd five levels deep, the browser will automatically enforce a 4 ms minimum value for the interval.

    Браузери можуть знати, що навіть більше stringent мінімальні значення для терміну під деякими circumstances, хоча вони повинні не бути спільними. Note also that the actual amount of time that elapses between calls to callback may be longer than given delay ; Виберіть Reasons for delays longer than specified in WindowOrWorkerGlobalScope.setTimeout() for examples.

    Ensure that execution duration is shorter than interval frequency

    Якщо є можливість, що ваш логічний може виконати тривалість до виконання лише в часі часу, це є відповідним тим, що ви є recursive call і наведена функція використовуючи setTimeout() . Для прикладу, якщо використовує setInterval() до поло на remote server протягом 5 seconds, мережевий термін, на невідповідному сервері, і host з інших повідомлень може запропонувати відповідь від завершення в його тривалий час. Як так, вам може бути виявлено, що ви потребуєте XHR потреби, які необхідно відновити в порядку.

    Дуже важливо розуміти, як працюють JavaScript таймери. Найчастіше їхня поведінка не збігається з нашим інтуїтивним сприйняттям багатопоточності, і це пов'язано з тим, що вони насправді виконуються в одному потоці. Давайте розглянемо чотири функції, за допомогою яких ми можемо керувати таймерами:

    • var id = setTimeout(fn, delay); - Створює простий таймер, який викличе цю функцію після заданої затримки. Функція повертає унікальний ID, за допомогою якого таймер може призупинитися.
    • var id = setInterval(fn, delay); - Схоже на setTimeout, але безперервно викликає функцію із заданим інтервалом (поки не буде зупинена).
    • clearInterval(id);, clearTimeout(id); - Приймає таймер ID (повертається однією з функцій, описаних вище) та зупиняє виконання callback"a.
    Головна ідея, яку слід розглянути, полягає в тому, що точність періоду затримки таймера не гарантується. Почнемо з того, що браузер виконує всі асинхронні JavaScript-події в одному потоці (такі як клік мишею або таймери) і тільки в той час, коли настала черга цієї події. Найкраще це демонструє наступна діаграма:

    На цьому малюнку досить багато інформації, яку потрібно засвоїти, але розуміння дасть вам глибше розуміння механізму роботи асинхронності виконання JavaScript. на цій діаграмі вертикально представлений час у мілісекундах, сині блоки показують блоки JavaScript коду, який було виконано. Наприклад, перший блок виконується загалом за 18мс, клік мишею блокує виконання приблизно 11мс тощо.

    JavaScript може виконувати лише одну порцію коду (через однопотокову природу виконання), кожна з яких блокує виконання інших асинхронних подій. Це означає, що при виникненні асинхронної події (такого як клік мишею, виклик таймера або завершення XMLHttp-запиту) він додається в чергу і виконується пізніше (реалізація, звичайно ж, варіюється в залежності від браузера, але давайте умовимося називати це чергою) .

    Для початку уявімо, що всередині JavaScript блоку стартують два таймери: setTimeout із затримкою 10мс і setInterval з такою самою затримкою. Залежно від того, коли стартує таймер, він спрацює у момент, коли ми ще не завершили перший блок коду. Зауважте, однак, що він не спрацьовує відразу (це неможливо через однопотоковість). Натомість відкладена функція потрапляє у чергу і виконується у наступний доступний момент.

    Також під час першого JavaScript блоку виникає клік мишею. Обробник цієї асинхронної події (а вона асинхронна, тому що ми не можемо його передбачити) не може бути виконаний безпосередньо в цей момент, тому він також потрапляє в чергу, як і таймер.

    Після того, як перший блок JavaScript коду був виконаний, браузер задається питанням «Що чекає на виконання?». У цьому випадку обробник кліка мишею та таймер перебувають у стані очікування. Браузер вибирає один з них (обробник кліка) та виконує його. Таймер чекатиме наступної доступної порції часу у черзі на виконання.

    Зауважте, що поки обробник кліка мишею виконується, спрацьовує перший interval-callback. Так само як і timer-callback, він буде поставлений у чергу. Проте, врахуйте, що коли знову спрацює interval (поки виконуватиметься timer-callback), він буде видалено з черги. Якби всі interval-callback" і потрапляли в чергу поки виконується великий шматок коду, це призвело б до того, що утворилася б купа функцій, що чекають виклику без періодів затримок між закінченням їх виконання. Натомість браузери прагнуть чекати поки не залишиться жодної функції у черзі перш ніж додати до черги ще одну.

    Таким чином, ми можемо спостерігати випадок, коли третя спрацьовування interval-callback збігається з тим моментом, коли він уже виконується. Це ілюструє важливу особливість: інтервали не дбають про те, що виконується зараз, вони будуть додані до черги без урахування періоду затримки між виконаннями.

    Нарешті, після того як другий interval-callback завершиться, ми побачимо, що не залишилося нічого, що JavaScript-движок повинен виконати. Це означає, що браузер знову чекає на появу нових асинхронних подій. Це станеться на позначці 50мс, де interval-callback спрацює знову. У цей момент не буде нічого, що блокувало б його, тому він спрацює негайно.

    Давайте розглянемо приклад, який добре ілюструє різницю між setTimeout та setInterval.
    setTimeout(function()( /* Some long block of code... */ setTimeout(arguments.callee, 10); ), 10); setInterval(function()( /* Some long block of code... */ ), 10);
    Ці два варіанти є еквівалентними на перший погляд, але насправді це не так. Код, що використовує setTimeout завжди матиме затримку хоча б 10мс після попереднього виклику (він може бути більшим, але ніколи не може бути меншим), тоді як код, що використовує setInterval, буде прагнути викликатися кожні 10мс незалежно від того, коли відпрацював попередній виклик.

    Давайте резюмуємо все сказане вище:
    - JavaScript движки використовують однопоточне середовище, перетворюючи асинхронні події в чергу, що очікує виконання,
    - Функції setTimeout та setInterval принципово по-різному виконуються в асинхронному коді,
    - Якщо таймер не може бути виконаний в даний момент, він буде відкладений до наступної точки виконання (яка буде довшою за бажану затримку),
    - Інтервали (setInterval) можуть виконуватися один за одним без затримок, якщо їхнє виконання займає більше часу, ніж зазначена затримка.

    Усе це надзвичайно важливою інформацією для розробки. Знання того, як працює JavaScript движок, особливо з великою кількістю асинхронних подій (що часто трапляється), закладає відмінний фундамент для побудови додатків.