renovations
This commit is contained in:
parent
c7d4c7e3ff
commit
e1948130f6
170 changed files with 1496 additions and 1161 deletions
|
@ -0,0 +1,17 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function printNumbersInterval() {
|
||||
var i = 1;
|
||||
var timerId = setInterval(function() {
|
||||
console.log(i);
|
||||
if (i == 20) clearInterval(timerId);
|
||||
i++;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// вызов
|
||||
printNumbersInterval();
|
||||
```
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Вывод чисел каждые 100мс
|
||||
|
||||
[importance 5]
|
||||
|
||||
Напишите функцию `printNumbersInterval()`, которая последовательно выводит в консоль числа от 1 до 20, с интервалом между числами 100мс. То есть, весь вывод должен занимать 2000мс, в течение которых каждые 100мс в консоли появляется очередное число.
|
||||
|
||||
Нажмите на кнопку, открыв консоль, для демонстрации:
|
||||
<script>
|
||||
function printNumbersInterval() {
|
||||
var i = 1;
|
||||
var timerId = setInterval(function() {
|
||||
console.log(i);
|
||||
if (i == 20) clearInterval(timerId);
|
||||
i++;
|
||||
}, 100);
|
||||
}
|
||||
</script>
|
||||
<button onclick="printNumbersInterval()">printNumbersInterval()</button>
|
||||
</script>
|
||||
|
||||
P.S. Функция должна использовать `setInterval`.
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function printNumbersTimeout20_100() {
|
||||
var i = 1;
|
||||
var timerId = setTimeout(function go() {
|
||||
console.log(i);
|
||||
if (i < 20) setTimeout(go, 100);
|
||||
i++;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// вызов
|
||||
printNumbersTimeout20_100();
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# Вывод чисел каждые 100мс, через setTimeout
|
||||
|
||||
[importance 5]
|
||||
|
||||
Сделайте то же самое, что в задаче [](/task/output-numbers-100ms), но с использованием рекурсивного `setTimeout` вместо `setInterval`.
|
|
@ -0,0 +1,5 @@
|
|||
**Нужно выбрать вариант 2, который гарантирует браузеру свободное время между выполнениями `highlight`.**
|
||||
|
||||
Первый вариант может загрузить процессор на 100%, если `highlight` занимает время, близкое к 10мс или, тем более, большее чем 10мс, т.к. таймер не учитывает время выполнения функции.
|
||||
|
||||
Что интересно, в обоих случаях браузер не будет выводить предупреждение о том, что скрипт занимает много времени. Но от 100% загрузки процессора возможны притормаживания других операций. В общем, это совсем не то, что мы хотим, поэтому вариант 2.
|
|
@ -0,0 +1,34 @@
|
|||
# Для подсветки setInterval или setTimeout?
|
||||
|
||||
[importance 5]
|
||||
|
||||
Стоит задача: реализовать подсветку синтаксиса в длинном коде при помощи JavaScript, для онлайн-редактора кода. Это требует сложных вычислений, особенно загружает процессор генерация дополнительных элементов страницы, визуально осуществляющих подсветку.
|
||||
|
||||
Поэтому решаем обрабатывать не весь код сразу, что привело бы к зависанию скрипта, а разбить работу на части: подсвечивать по 20 строк раз в 10мс.
|
||||
|
||||
Как мы знаем, есть два варианта реализации такой подсветки:
|
||||
|
||||
<ol>
|
||||
<li>Через `setInterval`, с остановкой по окончании работы:
|
||||
|
||||
```js
|
||||
timer = setInterval(function() {
|
||||
if (есть еще что подсветить) highlight();
|
||||
else clearInterval(timer);
|
||||
}, 10);
|
||||
```
|
||||
|
||||
</li>
|
||||
<li>Через рекурсивный `setTimeout`:
|
||||
|
||||
```js
|
||||
setTimeout(function go() {
|
||||
highlight();
|
||||
if (есть еще что подсветить) setTimeout(go, 10);
|
||||
}, 10);
|
||||
```
|
||||
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
Какой из них стоит использовать? Почему?
|
|
@ -0,0 +1,8 @@
|
|||
Ответы:
|
||||
<ul>
|
||||
<li>`alert` выведет `100000000`.</li>
|
||||
<li>**3**, срабатывание будет после окончания работы `hardWork`.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
Так будет потому, что вызов планируется на `100мс` от времени вызова `setTimeout`, но функция выполняется больше, чем `100мс`, поэтому к моменту ее окончания время уже подошло и отложенный вызов выполняется тут же.
|
|
@ -0,0 +1,31 @@
|
|||
# Что выведет setTimeout?
|
||||
|
||||
[importance 5]
|
||||
|
||||
В коде ниже запланирован запуск `setTimeout`, а затем запущена тяжёлая функция `f`, выполнение которой занимает более долгое время, чем интервал до срабатывания таймера.
|
||||
|
||||
Когда сработает `setTimeout`? Выберите нужный вариант:
|
||||
<ol>
|
||||
<li>До выполнения `f`.</li>
|
||||
<li>Во время выполнения `f`.</li>
|
||||
<li>Сразу же по окончании `f`.</li>
|
||||
<li>Через 100мс после окончания `f`.</li>
|
||||
</ol>
|
||||
|
||||
Что выведет `alert` в коде ниже?
|
||||
|
||||
```js
|
||||
setTimeout(function() {
|
||||
alert(i);
|
||||
}, 100);
|
||||
|
||||
var i;
|
||||
|
||||
function hardWork() {
|
||||
// время выполнения этого кода >100мс, сам код неважен
|
||||
for(i=0; i<1e8; i++) hardWork[i%2] = i;
|
||||
}
|
||||
|
||||
hardWork();
|
||||
```
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
Вызов `alert(i)` в `setTimeout` введет `100000001`.
|
||||
|
||||
Можете проверить это запуском:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var timer = setInterval(function() {
|
||||
i++;
|
||||
}, 10);
|
||||
|
||||
setTimeout(function() {
|
||||
clearInterval(timer);
|
||||
*!*
|
||||
alert(i); // (*)
|
||||
*/!*
|
||||
}, 50);
|
||||
|
||||
var i;
|
||||
|
||||
function f() {
|
||||
// точное время выполнения не играет роли
|
||||
// здесь оно заведомо больше 100мс
|
||||
for(i=0; i<1e8; i++) f[i%2] = i;
|
||||
}
|
||||
|
||||
f();
|
||||
```
|
||||
|
||||
Правильный вариант срабатывания: **3** (сразу же по окончании `f` один раз).
|
||||
|
||||
Планирование `setInterval` будет вызывать функцию каждые `10мс` после текущего времени. Но так как интерпретатор занят долгой функцией, то до конца ее работы никакого вызова не происходит.
|
||||
|
||||
За время выполнения `f` может пройти время, на которое запланированы несколько вызовов `setInterval`, но в этом случае остается только один, т.е. накопления вызовов не происходит. Такова логика работы `setInterval`.
|
||||
|
||||
После окончания текущего скрипта интерпретатор обращается к очереди запланированных вызовов, видит в ней `setInterval` и выполняет. А затем тут же выполняется `setTimeout`, очередь которого тут же подошла.
|
||||
|
||||
Итого, как раз и видим, что `setInterval` выполнился ровно 1 раз по окончании работы функции. Такое поведение кросс-браузерно.
|
|
@ -0,0 +1,44 @@
|
|||
# Что выведет после setInterval?
|
||||
|
||||
[importance 5]
|
||||
|
||||
В коде ниже запускается `setInterval` каждые 10мс, и через 50мс запланирована его отмена.
|
||||
|
||||
После этого запущена тяжёлая функция `f`, выполнение которой (мы точно знаем) потребует более 100мс.
|
||||
|
||||
Сработает ли `setInterval`, как и когда?
|
||||
|
||||
Варианты:
|
||||
<ol>
|
||||
<li>Да, несколько раз, *в процессе* выполнения `f`.</li>
|
||||
<li>Да, несколько раз, *сразу после* выполнения `f`.</li>
|
||||
<li>Да, один раз, *сразу после* выполнения `f`.</li>
|
||||
<li>Нет, не сработает.</li>
|
||||
<li>Может быть по-разному, как повезёт.</li>
|
||||
</ol>
|
||||
|
||||
Что выведет `alert` в строке `(*)`?
|
||||
|
||||
```js
|
||||
var i;
|
||||
var timer = setInterval(function() { // планируем setInterval каждые 10мс
|
||||
i++;
|
||||
}, 10);
|
||||
|
||||
setTimeout(function() { // через 50мс - отмена setInterval
|
||||
clearInterval(timer);
|
||||
*!*
|
||||
alert(i); // (*)
|
||||
*/!*
|
||||
}, 50);
|
||||
|
||||
// и запускаем тяжёлую функцию
|
||||
function f() {
|
||||
// точное время выполнения не играет роли
|
||||
// здесь оно заведомо больше 100мс
|
||||
for(i=0; i<1e8; i++) f[i%2] = i;
|
||||
}
|
||||
|
||||
f();
|
||||
```
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
Задача -- с небольшим "нюансом".
|
||||
|
||||
Есть браузеры, в которых на время работы JavaScript таймер "застывает", например таков IE. В них количество шагов будет почти одинаковым, +-1.
|
||||
|
||||
В других браузерах (Chrome) первый бегун будет быстрее.
|
||||
|
||||
Создадим реальные объекты `Runner` и запустим их для проверки:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function Runner() {
|
||||
this.steps = 0;
|
||||
|
||||
this.step = function() {
|
||||
this.doSomethingHeavy();
|
||||
this.steps++;
|
||||
};
|
||||
|
||||
function fib(n) {
|
||||
return n <= 1 ? n : fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
this.doSomethingHeavy = function() {
|
||||
for(var i=0; i<25; i++) {
|
||||
this[i] = fib(i);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var runner1 = new Runner();
|
||||
var runner2 = new Runner();
|
||||
|
||||
// запускаем бегунов
|
||||
var t1 = setInterval(function() {
|
||||
runner1.step();
|
||||
}, 15);
|
||||
|
||||
var t2 = setTimeout(function go() {
|
||||
runner2.step();
|
||||
t2 = setTimeout(go, 15);
|
||||
}, 15);
|
||||
|
||||
// кто сделает больше шагов?
|
||||
setTimeout(function() {
|
||||
clearInterval(t1);
|
||||
clearTimeout(t2);
|
||||
alert(runner1.steps);
|
||||
alert(runner2.steps);
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
Если бы в шаге `step()` не было вызова `doSomethingHeavy()`, то есть он бы не требовал времени, то количество шагов было бы почти равным.
|
||||
|
||||
Но так как у нас шаг, всё же, что-то делает, и функция `doSomethingHeavy()` специально написана таким образом, что она требует (небольшого) времени, то первый бегун успеет сделать больше шагов. Ведь в `setTimeout` пауза `15` мс будет *между* шагами, а `setInterval` шагает равномерно, каждые `15` мс. Получается чаще.
|
|
@ -0,0 +1,35 @@
|
|||
# Кто быстрее?
|
||||
|
||||
[importance 5]
|
||||
|
||||
Есть два бегуна:
|
||||
|
||||
```js
|
||||
var runner1 = new Runner();
|
||||
var runner2 = new Runner();
|
||||
```
|
||||
|
||||
У каждого есть метод `step()`, который делает шаг, увеличивая свойство `steps`.
|
||||
|
||||
Конкретный код метода `step()` не имеет значения, важно лишь что шаг делается не мгновенно, он требует небольшого времени.
|
||||
|
||||
Если запустить первого бегуна через `setInterval`, а второго -- через вложенный `setTimeout` -- какой сделает больше шагов за 5 секунд?
|
||||
|
||||
```js
|
||||
// первый?
|
||||
setInterval(function() {
|
||||
runner1.step();
|
||||
}, 15);
|
||||
|
||||
// или второй?
|
||||
setTimeout(function go() {
|
||||
runner2.step();
|
||||
setTimeout(go, 15);
|
||||
}, 15);
|
||||
|
||||
setTimeout(function() {
|
||||
alert(runner1.steps);
|
||||
alert(runner2.steps);
|
||||
}, 5000);
|
||||
```
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
function delay(f, ms) {
|
||||
|
||||
return function() {
|
||||
var savedThis = this;
|
||||
var savedArgs = arguments;
|
||||
|
||||
setTimeout(function() {
|
||||
f.apply(savedThis, savedArgs);
|
||||
}, ms);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
describe("delay", function() {
|
||||
before(function() {
|
||||
this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
|
||||
after(function() {
|
||||
this.clock.restore();
|
||||
});
|
||||
|
||||
it("вызывает функцию через указанный таймаут", function() {
|
||||
var start = Date.now();
|
||||
function f(x) {
|
||||
assert.equal(Date.now() - start, 1000);
|
||||
}
|
||||
f = sinon.spy(f);
|
||||
|
||||
var f1000 = delay(f, 1000);
|
||||
f1000("test");
|
||||
this.clock.tick(2000);
|
||||
assert(f.calledOnce, 'calledOnce check fails');
|
||||
});
|
||||
|
||||
it("передаёт аргументы и контекст", function() {
|
||||
var start = Date.now();
|
||||
var user = {
|
||||
sayHi: function(phrase, who) {
|
||||
assert.equal(this, user);
|
||||
assert.equal(phrase, "Привет");
|
||||
assert.equal(who, "Вася");
|
||||
assert.equal(Date.now() - start, 1500);
|
||||
}
|
||||
};
|
||||
|
||||
user.sayHi = sinon.spy(user.sayHi);
|
||||
|
||||
var spy = user.sayHi;
|
||||
user.sayHi = delay(user.sayHi, 1500);
|
||||
|
||||
user.sayHi("Привет", "Вася");
|
||||
|
||||
this.clock.tick(2000);
|
||||
|
||||
assert(spy.calledOnce, 'проверка calledOnce не сработала');
|
||||
});
|
||||
});
|
46
1-js/7-js-misc/3-setTimeout-setInterval/7-delay/solution.md
Normal file
46
1-js/7-js-misc/3-setTimeout-setInterval/7-delay/solution.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function delay(f, ms) {
|
||||
|
||||
*!*
|
||||
return function() {
|
||||
var savedThis = this;
|
||||
var savedArgs = arguments;
|
||||
|
||||
setTimeout(function() {
|
||||
f.apply(savedThis, savedArgs);
|
||||
}, ms);
|
||||
};
|
||||
*/!*
|
||||
|
||||
}
|
||||
|
||||
function f(x) {
|
||||
alert(x);
|
||||
}
|
||||
|
||||
var f1000 = delay(f, 1000);
|
||||
var f1500 = delay(f, 1500);
|
||||
|
||||
f1000("тест"); // выведет "тест" через 1000 миллисекунд
|
||||
f1500("тест2"); // выведет "тест2" через 1500 миллисекунд
|
||||
```
|
||||
|
||||
Обратим внимание на то, как работает обёртка:
|
||||
|
||||
```js
|
||||
return function() {
|
||||
var savedThis = this;
|
||||
var savedArgs = arguments;
|
||||
|
||||
setTimeout(function() {
|
||||
f.apply(savedThis , savedArgs);
|
||||
}, ms);
|
||||
};
|
||||
```
|
||||
|
||||
Именно обёртка возвращается декоратором `delay` и будет вызвана. Чтобы передать аргумент и контекст функции, вызываемой через `ms` миллисекунд, они копируются в локальные переменные `savedThis` и `savedArgs`.
|
||||
|
||||
Это один из самых простых, и в то же время удобных способов передать что-либо в функцию, вызываемую через `setTimeout`.
|
23
1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md
Normal file
23
1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Функция-задержка
|
||||
|
||||
[importance 5]
|
||||
|
||||
**Напишите функцию `delay(f, ms)`, которая возвращает обёртку вокруг `f`, задерживающую вызов на `ms` миллисекунд.**
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
function f(x) {
|
||||
alert(x);
|
||||
}
|
||||
|
||||
var f1000 = delay(f, 1000);
|
||||
var f1500 = delay(f, 1500);
|
||||
|
||||
f1000("тест"); // выведет "тест" через 1000 миллисекунд
|
||||
f1500("тест2"); // выведет "тест2" через 1500 миллисекунд
|
||||
```
|
||||
|
||||
Иначе говоря, `f1000` -- это "задержанный на 1000мс" вызов `f`.
|
||||
|
||||
В примере выше у функции только один аргумент, но `delay` должна быть универсальной: передавать любое количество аргументов и контекст `this`.
|
|
@ -0,0 +1,17 @@
|
|||
function debounce(f, ms) {
|
||||
|
||||
var state = null;
|
||||
|
||||
var COOLDOWN = 1;
|
||||
|
||||
return function() {
|
||||
if (state) return;
|
||||
|
||||
f.apply(this, arguments);
|
||||
|
||||
state = COOLDOWN;
|
||||
|
||||
setTimeout(function() { state = null }, ms);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
describe("debounce", function() {
|
||||
before(function() {
|
||||
this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
|
||||
after(function() {
|
||||
this.clock.restore();
|
||||
});
|
||||
|
||||
it("вызывает функцию не чаще чем раз в ms миллисекунд", function() {
|
||||
var log = '';
|
||||
function f(a) { log += a; }
|
||||
|
||||
f = debounce(f, 1000);
|
||||
|
||||
f(1); // выполнится сразу же
|
||||
f(2); // игнор
|
||||
|
||||
setTimeout(function() { f(3) }, 100); // игнор (рановато)
|
||||
setTimeout(function() { f(4) }, 1100); // выполнится (таймаут прошёл)
|
||||
setTimeout(function() { f(5) }, 1500); // игнор
|
||||
|
||||
this.clock.tick(5000);
|
||||
assert.equal(log, "14");
|
||||
});
|
||||
|
||||
it("сохраняет контекст вызова", function() {
|
||||
var obj = {
|
||||
f: function() {
|
||||
assert.equal(this, obj);
|
||||
}
|
||||
};
|
||||
|
||||
obj.f = debounce(obj.f, 1000);
|
||||
obj.f("test");
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function debounce(f, ms) {
|
||||
|
||||
var state = null;
|
||||
|
||||
var COOLDOWN = 1;
|
||||
|
||||
return function() {
|
||||
if (state) return;
|
||||
|
||||
f.apply(this, arguments);
|
||||
|
||||
state = COOLDOWN;
|
||||
|
||||
setTimeout(function() { state = null }, ms);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function f(x) { alert(x) }
|
||||
var f = debounce(f, 1000);
|
||||
|
||||
f(1); // 1, выполнится сразу же
|
||||
f(2); // игнор
|
||||
|
||||
setTimeout( function() { f(3) }, 100); // игнор (прошло только 100мс)
|
||||
setTimeout( function() { f(4) }, 1100); // 4, выполнится
|
||||
setTimeout( function() { f(5) }, 1500); // игнор
|
||||
```
|
||||
|
||||
Вызов `debounce` возвращает функцию-обёртку. Все необходимые данные для неё хранятся в замыкании.
|
||||
|
||||
При вызове ставится таймер и состояние `state` меняется на константу `COOLDOWN` ("в процессе охлаждения").
|
||||
|
||||
Последующие вызовы игнорируются, пока таймер не обнулит состояние.
|
23
1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md
Normal file
23
1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Вызов не чаще чем в N миллисекунд
|
||||
|
||||
[importance 5]
|
||||
|
||||
**Напишите функцию `debounce(f, ms)`, которая возвращает обёртку, которая передаёт вызов `f` не чаще, чем раз в `ms` миллисекунд.**
|
||||
|
||||
"Лишние" вызовы игнорируются. Все аргументы и контекст -- передаются.
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
function f() { ... }
|
||||
|
||||
var f = debounce(f, 1000);
|
||||
|
||||
f(1); // выполнится сразу же
|
||||
f(2); // игнор
|
||||
|
||||
setTimeout( function() { f(3) }, 100); // игнор (прошло только 100мс)
|
||||
setTimeout( function() { f(4) }, 1100); // выполнится
|
||||
setTimeout( function() { f(5) }, 1500); // игнор
|
||||
```
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
function throttle(func, ms) {
|
||||
|
||||
var isThrottled = false,
|
||||
savedArgs,
|
||||
savedThis;
|
||||
|
||||
function wrapper() {
|
||||
|
||||
if (isThrottled) {
|
||||
savedArgs = arguments;
|
||||
savedThis = this;
|
||||
return;
|
||||
}
|
||||
|
||||
func.apply(this, arguments);
|
||||
|
||||
isThrottled = true;
|
||||
|
||||
setTimeout(function() {
|
||||
isThrottled = false;
|
||||
if (savedArgs) {
|
||||
wrapper.apply(savedThis, savedArgs);
|
||||
savedArgs = savedThis = null;
|
||||
}
|
||||
}, ms);
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
describe("throttle(f, 1000)", function() {
|
||||
var f1000;
|
||||
var log = "";
|
||||
function f(a) { log += a; }
|
||||
|
||||
before(function() {
|
||||
f1000 = throttle(f, 1000);
|
||||
this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
|
||||
it("первый вызов срабатывает тут же", function() {
|
||||
f1000(1); // такой вызов должен сработать тут же
|
||||
assert.equal(log, "1");
|
||||
});
|
||||
|
||||
it("тормозит второе срабатывание до 1000мс", function() {
|
||||
f1000(2); // (тормозим, не прошло 1000мс)
|
||||
f1000(3); // (тормозим, не прошло 1000мс)
|
||||
// через 1000 мс запланирован вызов с последним аргументом
|
||||
|
||||
assert.equal(log, "1"); // пока что сработал только первый вызов
|
||||
|
||||
this.clock.tick(1000); // прошло 1000мс времени
|
||||
assert.equal(log, "13"); // log==13, т.к. сработал вызов f1000(3)
|
||||
});
|
||||
|
||||
it("тормозит третье срабатывание до 1000мс после второго", function() {
|
||||
this.clock.tick(100);
|
||||
f1000(4); // (тормозим, с последнего вызова прошло 100мс - менее 1000мс)
|
||||
this.clock.tick(100);
|
||||
f1000(5); // (тормозим, с последнего вызова прошло 200мс - менее 1000мс)
|
||||
this.clock.tick(700);
|
||||
f1000(6); // (тормозим, с последнего вызова прошло 900мс - менее 1000мс)
|
||||
|
||||
this.clock.tick(100); // сработал вызов с 6
|
||||
|
||||
assert.equal(log, "136");
|
||||
});
|
||||
|
||||
after(function() {
|
||||
this.clock.restore();
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
|
||||
```js
|
||||
function throttle(func, ms) {
|
||||
|
||||
var isThrottled = false,
|
||||
savedArgs,
|
||||
savedThis;
|
||||
|
||||
function wrapper() {
|
||||
|
||||
if (isThrottled) { // (2)
|
||||
savedArgs = arguments;
|
||||
savedThis = this;
|
||||
return;
|
||||
}
|
||||
|
||||
func.apply(this, arguments); // (1)
|
||||
|
||||
isThrottled = true;
|
||||
|
||||
setTimeout(function() {
|
||||
isThrottled = false; // (3)
|
||||
if (savedArgs) {
|
||||
wrapper.apply(savedThis, savedArgs);
|
||||
savedArgs = savedThis = null;
|
||||
}
|
||||
}, ms);
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
```
|
||||
|
||||
Шаги работы этой функции:
|
||||
<ol>
|
||||
<li>Декоратор `throttle` возвращает функцию-обёртку `wrapper`, которая при первом вызове запускает `func` и переходит в состояние "паузы" (`isThrottled = true`).</li>
|
||||
<li>В этом состоянии все новые вызовы запоминаются в замыкании через `savedArgs/savedThis`. Обратим внимание, что и контекст вызова и аргументы для нас одинаково важны и запоминаются одновременно. Только зная и то и другое, можно воспроизвести вызов правильно.</li>
|
||||
<li>Далее, когда пройдёт таймаут `ms` миллисекунд -- пауза будет снята, а `wrapper` -- запущен с последними аргументами и контекстом (если во время паузы были вызовы).</li>
|
||||
</ol>
|
||||
|
||||
Шаг `(3)` запускает именно не саму функцию, а снова `wrapper`, так как необходимо не только выполнить `func`, но и снова поставить выполнение на паузу. Получается последовательность "вызов - пауза.. вызов - пауза .. вызов - пауза ...", каждое выполнение в обязательном порядке сопровождается паузой после него. Это удобно описывается рекурсией.
|
50
1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md
Normal file
50
1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Тормозилка
|
||||
|
||||
[importance 5]
|
||||
|
||||
Напишите функцию `throttle(f, ms)` -- "тормозилку", которая возвращает обёртку, передающую вызов `f` не чаще, чем раз в `ms` миллисекунд.
|
||||
|
||||
**У этой функции должно быть важное существенное отличие от `debounce`:** если игнорируемый вызов оказался последним, т.е. после него до окончания задержки ничего нет -- то он выполнится.
|
||||
|
||||
Чтобы лучше понять, откуда взялось это требование, и как `throttle` должна работать -- разберём реальное применение, на которое и ориентирована эта задача.
|
||||
|
||||
**Например, нужно обрабатывать передвижения мыши.**
|
||||
|
||||
В JavaScript это делается функцией, которая будет запускаться при каждом микро-передвижении мыши и получать координаты курсора. По мере того, как мышь двигается, эта функция может запускаться очень часто, может быть 100 раз в секунду (каждые 10мс).
|
||||
|
||||
**Функция обработки передвижения должна обновлять некую информацию на странице.**
|
||||
|
||||
При этом обновление -- слишком "тяжёлый" процесс, чтобы делать его при каждом микро-передвижении. Имеет смысл делать его раз в 100мс, не чаще.
|
||||
|
||||
Пусть функция, которая осуществляет это обновление по передвижению, называется `onmousemove`.
|
||||
|
||||
Вызов `throttle(onmousemove, 100)`, по сути, предназначен для того, чтобы "притормаживать" обработку `onmousemove`. Технически, он должен возвращать обёртку, которая передаёт все вызовы `onmousemove`, но не чаще чем раз в 100мс.
|
||||
|
||||
**При этом промежуточные движения можно игнорировать, но мышь в конце концов где-то остановится. И это последнее, итоговое положение мыши обязательно нужно обработать!**
|
||||
|
||||
Визуально это даст следующую картину обработки перемещений мыши:
|
||||
<ol>
|
||||
<li>Первое обновление произойдёт сразу (это важно, посетитель тут же видит реакцию на своё действие).</li>
|
||||
<li>Дальше может быть много вызовов (микро-передвижений) с разными координатами, но пока не пройдёт 100мс -- ничего не будет.</li>
|
||||
<li>По истечении 100мс -- опять обновление, с последними координатами. Промежуточные микро-передвижения игнорированы.</li>
|
||||
<li>В конце концов мышь где-то остановится, обновление по окончании очередной паузы 100мс (иначе мы не знаем, последнее оно или нет) сработает с последними координатами.</li>
|
||||
</ol>
|
||||
|
||||
Ещё раз заметим -- задача из реальной жизни, и в ней принципиально важно, что *последнее* передвижение обрабатывается. Пользователь должен увидеть, где остановил мышь.
|
||||
|
||||
Пример использования:
|
||||
|
||||
```js
|
||||
var f = function(a) { console.log(a) };
|
||||
|
||||
// затормозить функцию до одного раза в 1000 мс
|
||||
var f1000 = throttle(f, 1000);
|
||||
|
||||
f1000(1); // выведет 1
|
||||
f1000(2); // (тормозим, не прошло 1000мс)
|
||||
f1000(3); // (тормозим, не прошло 1000мс)
|
||||
|
||||
// когда пройдёт 1000мс...
|
||||
// выведет 3, промежуточное значение 2 игнорируется
|
||||
```
|
||||
|
318
1-js/7-js-misc/3-setTimeout-setInterval/article.md
Normal file
318
1-js/7-js-misc/3-setTimeout-setInterval/article.md
Normal file
|
@ -0,0 +1,318 @@
|
|||
# setTimeout и setInterval
|
||||
|
||||
Почти все реализации JavaScript имеют внутренний таймер-планировщик, который позволяет задавать вызов функции через заданный период времени.
|
||||
|
||||
В частности, эта возможность поддерживается в браузерах и в сервере Node.JS.
|
||||
|
||||
[cut]
|
||||
## setTimeout
|
||||
|
||||
Синтаксис:
|
||||
|
||||
```js
|
||||
var timerId = setTimeout(func/code, delay[, arg1, arg2...])
|
||||
```
|
||||
|
||||
Параметры:
|
||||
|
||||
<dl>
|
||||
<dt>`func/code`</dt>
|
||||
<dd>Функция или строка кода для исполнения.
|
||||
Строка поддерживается для совместимости, использовать её не рекомендуется.</dd>
|
||||
<dt>`delay`</dt>
|
||||
<dd>Задержка в милисекундах, 1000 милисекунд равны 1 секунде.</dd>
|
||||
<dt>`arg1`, `arg2`...</dt>
|
||||
<dd>Аргументы, которые нужно передать функции. Не поддерживаются в IE9-.</dd>
|
||||
</dl>
|
||||
|
||||
Исполнение функции произойдёт спустя время, указанное в параметре `delay`.
|
||||
|
||||
Например, следующий код вызовет `func()` через одну секунду:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function func() {
|
||||
alert('Привет');
|
||||
}
|
||||
|
||||
*!*
|
||||
setTimeout(func, 1000);
|
||||
*/!*
|
||||
```
|
||||
|
||||
С передачей аргументов (не сработает в IE9-):
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function func(phrase, who) {
|
||||
alert(phrase + ', ' + who);
|
||||
}
|
||||
|
||||
*!*
|
||||
setTimeout(func, 1000, "Привет", "Вася"); // Привет, Вася
|
||||
*/!*
|
||||
```
|
||||
|
||||
Если первый аргумент является строкой, то интерпретатор создаёт анонимную функцию из этой строки.
|
||||
|
||||
То есть такая запись тоже сработает:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
setTimeout("alert('Привет')", 1000);
|
||||
```
|
||||
|
||||
Однако, использование строк не рекомендуется, так как они могут вызвать проблемы при минимизации кода, и, вообще, сама возможность использовать строку сохраняется лишь для совместимости.
|
||||
|
||||
Вместо них используйте анонимные функции, вот так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
setTimeout(function() { alert('Привет') }, 1000);
|
||||
```
|
||||
|
||||
### Отмена исполнения clearTimeout
|
||||
|
||||
Функция `setTimeout` возвращает числовой идентификатор таймера `timerId`, который можно использовать для отмены действия.
|
||||
|
||||
Синтаксис:
|
||||
|
||||
```js
|
||||
var timerId = setTimeout(...);
|
||||
clearTimeout(timerId);
|
||||
```
|
||||
|
||||
В следующем примере мы ставим таймаут, а затем удаляем (передумали). В результате ничего не происходит.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var timerId = setTimeout(function() { alert(1) }, 1000);
|
||||
alert(timerId); // число - идентификатор таймера
|
||||
|
||||
clearTimeout(timerId);
|
||||
alert(timerId); // всё ещё число, оно не обнуляется после отмены
|
||||
```
|
||||
|
||||
Как видно из `alert`, в браузере идентификатор таймера является обычным числом. Другие JavaScript-окружения, например Node.JS, могут возвращать объект таймера, с дополнительными методами.
|
||||
|
||||
**Такие разночтения вполне соответствуют стандарту просто потому, что в спецификации JavaScript про таймеры нет ни слова.**
|
||||
|
||||
Таймеры -- это надстройка над JavaScript, которая описана в [секции Timers](http://www.w3.org/TR/html5/webappapis.html#timers) стандарта HTML5 для браузеров и в [документации к Node.JS](http://nodejs.org/docs/latest/api/timers.html) -- для сервера.
|
||||
|
||||
## setInterval
|
||||
|
||||
Метод `setInterval` имеет синтаксис, аналогичный `setTimeout`.
|
||||
|
||||
```js
|
||||
var timerId = setInterval(func/code, delay[, arg1, arg2...])
|
||||
```
|
||||
|
||||
Смысл аргументов -- тот же самый. Но, в отличие от `setTimeout`, он запускает выполнение функции не один раз, а регулярно повторяет её через указанный интервал времени. Остановить исполнение можно вызовом `clearInterval(timerId)`.
|
||||
|
||||
Следующий пример при запуске станет выводить сообщение каждые две секунды, пока не пройдёт 5 секунд:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
// начать повторы с интервалом 2 сек
|
||||
var timerId = setInterval(function() {
|
||||
alert("тик");
|
||||
}, 2000);
|
||||
|
||||
// через 5 сек остановить повторы
|
||||
setTimeout(function() {
|
||||
clearInterval(timerId);
|
||||
alert('стоп');
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
[smart header="Модальные окна замораживают время в Chrome/Opera/Safari"]
|
||||
Что будет, если долго не жать `OK` на появившемся `alert`? Это зависит от браузера.
|
||||
|
||||
В браузерах Chrome, Opera и Safari внутренний таймер "заморожен" во время показа `alert/confirm/prompt`. А вот в IE и Firefox внутренний таймер продолжит идти.
|
||||
|
||||
Поэтому, если закрыть `alert` после небольшой паузы, то в Firefox/IE следующий `alert` будет показан сразу же (время подошло), а в Chrome/Opera/Safari -- только через 2 секунды после закрытия.
|
||||
[/smart]
|
||||
|
||||
|
||||
### Рекурсивный setTimeout
|
||||
|
||||
Важная альтернатива `setInterval` -- рекурсивный `setTimeout`:
|
||||
|
||||
```js
|
||||
/** вместо:
|
||||
var timerId = setInterval(function() {
|
||||
alert("тик");
|
||||
}, 2000);
|
||||
*/
|
||||
|
||||
var timerId = setTimeout(function tick() {
|
||||
alert("тик");
|
||||
*!*
|
||||
timerId = setTimeout(tick, 2000);
|
||||
*/!*
|
||||
}, 2000);
|
||||
```
|
||||
|
||||
В коде выше следующее выполнение планируется сразу после окончания предыдущего.
|
||||
|
||||
**Рекурсивный `setTimeout` -- более гибкий метод тайминга, чем `setInterval`, так как время до следующего выполнения можно запланировать по-разному, в зависимости от результатов текущего.**
|
||||
|
||||
Например, у нас есть сервис, который в 5 секунд опрашивает сервер на предмет новых данных. В случае, если сервер перегружен, можно увеличивать интервал опроса до 10, 20, 60 секунд... А потом вернуть обратно, когда всё нормализуется.
|
||||
|
||||
Если у нас регулярно проходят грузящие процессор задачи, то мы можем оценивать время, потраченное на их выполнение, и планировать следующий запуск раньше или позже.
|
||||
|
||||
**Рекурсивный `setTimeout` гарантирует паузу между вызовами, `setInterval` -- нет.**
|
||||
|
||||
Давайте сравним два кода. Первый использует `setInterval`:
|
||||
|
||||
```js
|
||||
var i = 1;
|
||||
setInterval(function() {
|
||||
func(i);
|
||||
}, 100);
|
||||
```
|
||||
|
||||
Второй использует рекурсивный `setTimeout`:
|
||||
|
||||
```js
|
||||
var i = 1;
|
||||
setTimeout(function run() {
|
||||
func(i);
|
||||
setTimeout(run, 100);
|
||||
}, 100);
|
||||
```
|
||||
|
||||
При `setInterval` внутренний таймер будет срабатывать чётко каждые `100` мс и вызывать `func(i)`:
|
||||
|
||||
<img src="setinterval-interval.svg">
|
||||
|
||||
Вы обратили внимание?...
|
||||
|
||||
**Реальная пауза между вызовами `func` при `setInterval` меньше, чем указана в коде!**
|
||||
|
||||
Это естественно, ведь время работы функции никак не учитывается, оно "съедает" часть интервала.
|
||||
|
||||
Возможно и такое что `func` оказалась сложнее, чем мы рассчитывали и выполнялась дольше, чем 100мс.
|
||||
|
||||
В этом случае интерпретатор будет ждать, пока функция завершится, затем проверит таймер и, если время вызова `setInterval` уже подошло (или прошло), то следующий вызов произойдёт *сразу же*.
|
||||
|
||||
**Если функция и выполняется дольше, чем пауза `setInterval`, то вызовы будут происходить вообще без перерыва.**
|
||||
|
||||
Исключением является IE, в котором таймер "застывает" во время выполнения JavaScript.
|
||||
|
||||
А так будет выглядить картинка с рекурсивным `setTimeout`:
|
||||
|
||||
<img src="settimeout-interval.svg">
|
||||
|
||||
**При рекурсивном `setTimeout` задержка всегда фиксирована и равна 100мс.**
|
||||
|
||||
Это происходит потому, что каждый новый запуск планируется только после окончания текущего.
|
||||
|
||||
[smart header="Управление памятью"]
|
||||
Сборщик мусора в JavaScript не чистит функции, назначенные в таймерах, пока таймеры актуальны.
|
||||
|
||||
При передаче функции в `setInterval/setTimeout` создаётся внутренняя ссылка на неё, через которую браузер её будет запускать, и которая препятствует удалению из памяти, даже если функция анонимна.
|
||||
|
||||
```js
|
||||
// Функция будет жить в памяти, пока не сработал (или не был очищен) таймер
|
||||
setTimeout(function() {}, 100);
|
||||
```
|
||||
|
||||
<ul>
|
||||
<li>Для `setTimeout` -- внутренняя ссылка исчезнет после исполнения функции.</li>
|
||||
<li>Для `setInterval` -- ссылка исчезнет при очистке таймера.</li>
|
||||
</ul>
|
||||
|
||||
Так как функция также тянет за собой всё замыкание, то ставшие неактуальными, но не отменённые `setInterval` могут приводить к излишним тратам памяти.
|
||||
[/smart]
|
||||
|
||||
|
||||
## Минимальная задержка таймера
|
||||
|
||||
У браузерного таймера есть минимальная возможная задержка. Она меняется от примерно нуля до 4мс в современных браузерах. В более старых она может быть больше и достигать 15мс.
|
||||
|
||||
По [стандарту](http://www.w3.org/TR/html5/webappapis.html#timers), минимальная задержка составляет 4мс. Так что нет разницы между `setTimeout(..,1)` и `setTimeout(..,4)`.
|
||||
|
||||
Посмотреть минимальное разрешение "вживую" можно на следующем примере.
|
||||
|
||||
**В примере ниже каждая полоска удлиняется вызовом `setInterval` с указанной на ней задержкой -- от 0мс (сверху) до 20мс (внизу).**
|
||||
|
||||
Позапускайте его в различных браузерах. Вы заметите, что несколько первых полосок анимируются с одинаковой скоростью. Это как раз потому, что слишком маленькие задержки таймер не различает.
|
||||
|
||||
[iframe border="1" src="setInterval-anim" link edit]
|
||||
|
||||
[warn]
|
||||
В Internet Explorer, нулевая задержка `setInterval(.., 0)` не сработает. Это касается именно `setInterval`, т.е. `setTimeout(.., 0)` работает нормально.
|
||||
[/warn]
|
||||
|
||||
## Реальная частота срабатывания
|
||||
|
||||
В ряде ситуаций таймер будет срабатывать реже, чем обычно. Задержка между вызовами `setInterval(..., 4)` может быть не 4мс, а 30мс или даже 1000мс.
|
||||
|
||||
<ul>
|
||||
<li>Большинство браузеров (десктопных в первую очередь) продолжают выполнять `setTimeout/setInterval`, даже если вкладка неактивна.
|
||||
|
||||
При этом ряд из них (Chrome, FF, IE10) снижают минимальную частоту таймера, до 1 раза в секунду. Получается, что в "фоновой" вкладке будет срабатывать таймер, но редко.</li>
|
||||
<li>При работе от батареи, в ноутбуке -- браузеры тоже могут снижать частоту, чтобы реже выполнять код и экономить заряд батареи. Особенно этим известен IE. Снижение может достигать нескольких раз, в зависимости от настроек.</li>
|
||||
<li>При слишком большой загрузке процессора JavaScript может не успевать обрабатывать таймеры вовремя. При этом некоторые запуски `setInterval` будут пропущены.</li>
|
||||
</ul>
|
||||
|
||||
**Вывод: на частоту 4мс стоит ориентироваться, но не стоит рассчитывать.**
|
||||
|
||||
[online]
|
||||
Посмотрим снижение частоты в действии на небольшом примере.
|
||||
|
||||
|
||||
При клике на кнопку ниже запускается `setInterval(..., 90)`, который выводит список интервалов времени между 25 последними срабатываниями таймера. Запустите его. Перейдите на другую вкладку и вернитесь.
|
||||
|
||||
<div id="timer-interval-log"></div>
|
||||
|
||||
<button onclick="timerIntervalLog()">Запустить повтор с интервалом в 90 мс</button>
|
||||
<button onclick="clearInterval(timerIntervalLogTimer)">Остановить повтор</button>
|
||||
|
||||
<script>
|
||||
var timerIntervalLogTimer;
|
||||
function timerIntervalLog() {
|
||||
var arr = [];
|
||||
var d = new Date;
|
||||
timerIntervalLogTimer = setInterval(function() {
|
||||
var diff = new Date - d;
|
||||
if (diff > 100) diff = '<span style="color:red">'+diff+'</span>';
|
||||
arr.push( diff );
|
||||
if (arr.length > 25) arr.shift();
|
||||
document.getElementById('timer-interval-log').innerHTML = arr;
|
||||
d = new Date;
|
||||
}, 90);
|
||||
}
|
||||
</script>
|
||||
|
||||
Если ваш браузер увеличивает таймаут при фоновом выполнении вкладки, то вы увидите увеличенные интервалы, помеченные <span style="color:red">красным</span>.
|
||||
|
||||
Кроме того, вы заметите, что таймер не является идеально точным ;)
|
||||
[/online]
|
||||
|
||||
## Разбивка долгих скриптов
|
||||
|
||||
Нулевой или небольшой таймаут также используют, чтобы разорвать поток выполнения "тяжелых" скриптов.
|
||||
|
||||
Например, скрипт для подсветки синтаксиса должен проанализировать код, создать много цветных элементов для подсветки и добавить их в документ -- на большом файле это займёт много времени, браузер может даже подвиснуть, что неприемлемо.
|
||||
|
||||
Для того, чтобы этого избежать, сложная задача разбивается на части, выполнение каждой части запускается через мини-интервал после предыдущей, чтобы дать браузеру время.
|
||||
|
||||
Например, осуществляется анализ и подсветка первых 100 строк, затем через 20 мс -- следующие 100 строк и так далее. При этом можно подстраиваться под CPU посетителя: замерять время на анализ 100 строк и, если процессор хороший, то в следующий раз обработать 200 строк, а если плохой -- то 50. В итоге подсветка будет работать с адекватной быстротой и без тормозов на любых текстах и компьютерах.
|
||||
|
||||
## Итого
|
||||
|
||||
<ul>
|
||||
<li>Методы `setInterval(func, delay)` и `setTimeout(func, delay)` позволяют запускать `func` регулярно/один раз через `delay` миллисекунд.</li>
|
||||
<li>Оба метода возвращают идентификатор таймера. Его используют для остановки выполнения вызовом `clearInterval/clearTimeout`.</li>
|
||||
<li>В случаях, когда нужно гарантировать задержку между регулярными вызовами или гибко её менять, вместо `setInterval` используют рекурсивный `setTimeout`.</li>
|
||||
<li>Минимальная задержка по стандарту составляет `4мс`. Браузеры соблюдают этот стандарт, но некоторые другие среды для выполнения JS, например Node.JS, могут предоставить и меньше задержки.</li>
|
||||
<li>В реальности срабатывания таймера могут быть гораздо реже, чем назначено, например если процессор перегружен, вкладка находится в фоновом режиме, ноутбук работает от батареи или по какой-то иной причине.</li>
|
||||
|
||||
Браузерных особенностей почти нет, разве что вызов `setInterval(..., 0)` с нулевой задержкой в IE недопустим, нужно указывать `setInterval(..., 1)`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
49
1-js/7-js-misc/3-setTimeout-setInterval/setInterval-anim.view/index.html
Executable file
49
1-js/7-js-misc/3-setTimeout-setInterval/setInterval-anim.view/index.html
Executable file
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style> div { height: 18px; margin: 1px; background-color:green; } </style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input type="button" id="start" value="Старт">
|
||||
<input type="button" id="stop" value="Стоп" disabled>
|
||||
|
||||
<script>
|
||||
for (var i=0; i<=20; i+=2) {
|
||||
document.write('<div>'+i+'</div>');
|
||||
}
|
||||
|
||||
var startButton = document.getElementById('start');
|
||||
var stopButton = document.getElementById('stop');
|
||||
|
||||
var timers = [];
|
||||
|
||||
stopButton.onclick = function() {
|
||||
startButton.disabled = false;
|
||||
stopButton.disabled = true;
|
||||
|
||||
for(var i=0; i<timers.length; i++) clearInterval(timers[i]);
|
||||
timers = [];
|
||||
}
|
||||
|
||||
startButton.onclick = function() {
|
||||
startButton.disabled = true;
|
||||
stopButton.disabled = false;
|
||||
|
||||
var divs = document.getElementsByTagName('div');
|
||||
for (var i=0; i<divs.length; i++) {
|
||||
animateDiv(divs, i);
|
||||
}
|
||||
}
|
||||
|
||||
function animateDiv(divs, i) {
|
||||
var div = divs[i], speed = div.innerHTML;
|
||||
timers[i] = setInterval(function() {
|
||||
div.style.width = (parseInt(div.style.width||0) + 2) % 400 + 'px'
|
||||
}, speed);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="631px" height="223px" viewBox="0 0 631 223" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>setinterval-interval</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="setinterval-interval" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<path d="M32.5,122.5 L582.5,122.5" id="Line" stroke="#979797" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc" sketch:type="MSLayerGroup" transform="translate(128.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(1)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(1)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc-2" sketch:type="MSLayerGroup" transform="translate(271.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(2)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(2)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc-3" sketch:type="MSLayerGroup" transform="translate(405.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(3)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(3)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<text id="100" sketch:type="MSTextLayer" font-family="Consolas" font-size="18" font-weight="normal" fill="#000000">
|
||||
<tspan x="115" y="183">100</tspan>
|
||||
</text>
|
||||
<text id="200" sketch:type="MSTextLayer" font-family="Consolas" font-size="18" font-weight="normal" fill="#000000">
|
||||
<tspan x="259" y="183">200</tspan>
|
||||
</text>
|
||||
<text id="300" sketch:type="MSTextLayer" font-family="Consolas" font-size="18" font-weight="normal" fill="#000000">
|
||||
<tspan x="394" y="183">300</tspan>
|
||||
</text>
|
||||
<path d="M221.5,122.5 L271.5,122.5" id="Line" stroke="#4990E2" stroke-width="3" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M364.5,122.5 L405.5,122.5" id="Line-2" stroke="#4990E2" stroke-width="3" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="631px" height="223px" viewBox="0 0 631 223" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>settimeout-interval</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="settimeout-interval" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<path d="M32.5,122.5 L582.5,122.5" id="Line" stroke="#979797" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc" sketch:type="MSLayerGroup" transform="translate(48.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(1)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(1)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc-2" sketch:type="MSLayerGroup" transform="translate(242.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(2)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(2)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="Rectangle-1-+-func(1)-+-noun_60230_cc-3" sketch:type="MSLayerGroup" transform="translate(436.000000, 41.000000)">
|
||||
<rect id="Rectangle-1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" x="3" y="60" width="90" height="40"></rect>
|
||||
<text id="func(3)" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||
<tspan x="25" y="84">func(3)</tspan>
|
||||
</text>
|
||||
<g id="noun_60230_cc" fill="#000000" sketch:type="MSShapeGroup">
|
||||
<path d="M22.5818182,19.3424658 L12.9113636,16.4383562 L20.4909091,0.273972603 L0.470454545,21.0958904 L10.1931818,24 L4.28636364,39.890411 L22.5818182,19.3424658 L22.5818182,19.3424658 Z M2.19545455,20.6575342 L17.3022727,4.93150685 L11.6045455,17.0410959 L20.8568182,19.7808219 L6.9,35.6164384 L11.4477273,23.3972603 L2.19545455,20.6575342 L2.19545455,20.6575342 Z" id="Shape"></path>
|
||||
</g>
|
||||
<path d="M3,114.5 L3,44.5" id="Line" stroke="#373535" stroke-width="2" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<text id="100" sketch:type="MSTextLayer" font-family="Consolas" font-size="18" font-weight="normal" fill="#000000">
|
||||
<tspan x="179" y="201">100</tspan>
|
||||
</text>
|
||||
<text id="100" sketch:type="MSTextLayer" font-family="Consolas" font-size="18" font-weight="normal" fill="#000000">
|
||||
<tspan x="372" y="201">100</tspan>
|
||||
</text>
|
||||
<path d="M142.5,122.5 L242.5,122.5" id="Line" stroke="#4990E2" stroke-width="3" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
<g id="Line-3" sketch:type="MSLayerGroup" transform="translate(142.000000, 171.000000)" stroke-linecap="square" stroke="#4990E2">
|
||||
<path d="M0.5,5.5 L100.5,5.5" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M92.5,5.5 L100.5,0.5" id="Line-5" sketch:type="MSShapeGroup" transform="translate(96.500000, 3.000000) scale(-1, 1) translate(-96.500000, -3.000000) "></path>
|
||||
<path d="M0.5,10.5 L8.5,5.5" id="Line-6" sketch:type="MSShapeGroup" transform="translate(4.500000, 8.000000) scale(-1, 1) translate(-4.500000, -8.000000) "></path>
|
||||
<path d="M92.5,10.5 L100.5,5.5" id="Line" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M0.5,5.5 L8.5,0.5" id="Line-4" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="Line-7" sketch:type="MSLayerGroup" transform="translate(336.000000, 171.000000)" stroke="#4990E2" stroke-linecap="square">
|
||||
<path d="M0.5,5.5 L100.5,5.5" id="Line-3" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M92.5,5.5 L100.5,0.5" id="Line-5" sketch:type="MSShapeGroup" transform="translate(96.500000, 3.000000) scale(-1, 1) translate(-96.500000, -3.000000) "></path>
|
||||
<path d="M0.5,10.5 L8.5,5.5" id="Line-6" sketch:type="MSShapeGroup" transform="translate(4.500000, 8.000000) scale(-1, 1) translate(-4.500000, -8.000000) "></path>
|
||||
<path d="M92.5,10.5 L100.5,5.5" id="Line" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M0.5,5.5 L8.5,0.5" id="Line-4" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<path d="M336.5,122.5 L436.5,122.5" id="Line-2" stroke="#4990E2" stroke-width="3" stroke-linecap="square" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue