|
1 | 1 | ### `setTimeout` и `setInterval`
|
2 | 2 |
|
3 |
| -Поскольку JavaScript поддерживает асинхронность, есть возможность запланировать выполнение функции, используя функции `setTimeout` и `setInterval`. |
| 3 | +В виду того, что JavaScript умеет совершать асинхронные операции, есть возможность запланировать отложенное выполнение пользовательской функции, используя предназначенные для этого функции `setTimeout` и `setInterval`. |
4 | 4 |
|
5 |
| -> **Замечание:** Таймауты **не** являются частью стандарта ECMAScript, они были разработаны как раздел спецификации[DOM][1]. |
| 5 | +> **Замечание:** Таймауты **не** являются частью стандарта ECMAScript, они были разработаны будучи частью спецификации[DOM][1]. |
6 | 6 |
|
7 | 7 | function foo() {}
|
8 | 8 | var id = setTimeout(foo, 1000); // возвращает число > 0
|
9 | 9 |
|
10 |
| -Функция `setTimeout` возвращает идентификатор таймаута и планирует вызвать `foo` через, **примерно**, тысячу миллисекунд. Фунция `foo` при этом будет вызвана ровно **один** раз. |
| 10 | +Функция `setTimeout` возвращает идентификатор назначенного таймаута и откладывает вызов `foo` на, **примерно**, тысячу миллисекунд. Фунция `foo`, при этом, будет вызвана только **один** раз. |
11 | 11 |
|
12 | 12 | В зависимости от разрешения таймера в используемом для запуска кода движке JavaScript, а также с учётом того, что JavaScript является однопоточным языком и посторонний код может заблокировать выполнение потока, нет **никакой** гарантии, что переданный код будет выполнен ровно через указанное в вызове `setTimeout` время.
|
13 | 13 |
|
14 |
| -Переданная первым параметром функция будет вызвана как *глобальный объект* — это значит, что оператор [`this`](#function.this) в вызываемой функции будет ссылаться на этот самый объект. |
| 14 | +Функция, переданная первым параметром, будет вызвана в контексте *глобального объекта* — это значит, что оператор [`this`](#function.this) в вызываемой функции будет ссылаться на тот самый глобальный объект. |
15 | 15 |
|
16 | 16 | function Foo() {
|
17 | 17 | this.value = 42;
|
|
26 | 26 |
|
27 | 27 | > **Замечание:** Поскольку `setTimeout` принимает **объект функции** в качестве первого параметра, часто совершается ошибка в использовании `setTimeout(foo(), 1000)`, при котором будет использоваться **возвращённое значение** от вызова функции `foo`, а **не** вызываться сама функция `foo`. В большинстве случаев ошибка пройдёт незамеченной, а в случае если функция возвращает `undefined`, `setTimeout` вообще **не** породит никакой ошибки.
|
28 | 28 |
|
29 |
| -### Поочерёдные вызовы с использованием `setInterval` |
| 29 | +### Очереди вызовов с `setInterval` |
30 | 30 |
|
31 |
| -`setTimeout` вызывает функцию единожды; `setInterval` — как и предполагает название — вызывает функцию **каждые** `X` миллисекунд. И его использование не рекомендуется. |
| 31 | +`setTimeout` вызывает функцию единожды; `setInterval` — как и предполагает название — вызывает функцию **каждые** `X` миллисекунд. И использовать его не рекомендуется. |
32 | 32 |
|
33 |
| -В то время, когда исполняющийся код будет блокироваться во время вызова с таймаутом, `setInterval` будет продолжать планировать последующие вызовы переданной функции. Это может (особенно в случае небольших интервалов) повлечь за собой выстраивание вызовов функций в очередь. |
| 33 | +В то время как, если применять `setTimeout`, исполняющийся в данный момент код будет блокировать запланированный — `setInterval` будет продолжать планировать последующие вызовы переданной функции. Это может, особенно при указании небольших интервалов, повлечь за собой выстраивание функций в ожидающую очередь. |
34 | 34 |
|
35 | 35 | function foo(){
|
36 |
| - // что-то, что выполняется одну секунду |
| 36 | + // что-то, выполняющееся одну секунду или более |
37 | 37 | }
|
38 | 38 | setInterval(foo, 1000);
|
39 | 39 |
|
40 |
| -В приведённом коде `foo` выполнится один раз и заблокирует этим главный поток на одну секунду. |
| 40 | +В приведённом примере `foo` в первый же раз заблокирует своим процессом главный поток на одну секунду. |
41 | 41 |
|
42 | 42 | Пока `foo` блокирует код, `setInterval` продолжает планировать последующие её вызовы. Теперь, когда первая `foo` закончила выполнение, в очереди будут уже **десять** ожидающих выполнения вызовов `foo`.
|
43 | 43 |
|
44 | 44 | ### Разбираемся с потенциальной блокировкой кода
|
45 | 45 |
|
46 |
| -Самый простой и контролируемый способ — использовать `setTimeout` внутри самой функции. |
| 46 | +Самый простой и наиболее легко контролируемый способ — использовать `setTimeout` внутри такой функции. |
47 | 47 |
|
48 | 48 | function foo(){
|
49 |
| - // что-то, выполняющееся одну секунду |
| 49 | + // что-то, выполняющееся одну секунду или более |
50 | 50 | setTimeout(foo, 1000);
|
51 | 51 | }
|
52 | 52 | foo();
|
53 | 53 |
|
54 | 54 | Такой способ не только инкапсулирует вызов `setTimeout`, но и предотвращает от очередей блокирующих вызовов и при этом обеспечивает дополнительный контроль. Сама функция `foo` теперь принимает решение, хочет ли она запускаться ещё раз или нет.
|
55 | 55 |
|
56 |
| -### Очистка таймаутов вручную |
| 56 | +(''прим. перев.'' — такая техника теперь активно используется при использовании браузерного метода `requestAnimationFrame` для анимации, работающей на `canvas`). |
57 | 57 |
|
58 |
| -Удаление таймаутов и интервалов работает через передачу соответствуюего идентификатора либо в функцию `clearTimeout`, либо в функцию `clearInterval` — в зависимости от того, какая функция `set...` использовалась для его получения. |
| 58 | +### Сброс таймаутов вручную |
| 59 | + |
| 60 | +Удалить таймаут или интервал можно посредством передачи соответствующего идентификатора либо в функцию `clearTimeout`, либо в функцию `clearInterval` — в зависимости от того, какая функция `set...` использовалась для его создания. |
59 | 61 |
|
60 | 62 | var id = setTimeout(foo, 1000);
|
61 | 63 | clearTimeout(id);
|
62 | 64 |
|
63 |
| -### Очистка всех таймаутов |
| 65 | +### Сброс всех таймаутов |
64 | 66 |
|
65 |
| -Из-за того, что встроенного метода для удаления всех таймаутов и/или интервалов не существует, для достижения этой цели приходится использовать брутфорс. |
| 67 | +Из-за того, что встроенного метода для удаления всех созданных таймаутов и/или интервалов не существует, для успешного достижения этой цели приходится использовать силу. |
66 | 68 |
|
67 |
| - // удаляем "все" таймауты |
| 69 | + // сбрасываем «все» таймауты |
68 | 70 | for(var i = 1; i < 1000; i++) {
|
69 | 71 | clearTimeout(i);
|
70 | 72 | }
|
71 | 73 |
|
72 |
| -Вполне могут остаться таймауты, которые не будут захвачены этим произвольным числом; так что всё же рекомендуется следить за идентификаторами всех создающихся таймаутов, засчёт чего их можно будет удалять индивидуально. |
| 74 | +Впрочем, с таким кодом, вполне могут остаться «живыми» таймауты, которые не окажутся охвачены настолько произвольным числом. |
| 75 | + |
| 76 | +Есть и другой способ воплотить желаемое — условиться, что значения ID, выдающихся таймаутам, постоянно увеличиваются — с каждым новыми вызовом `setTimeout`. |
| 77 | + |
| 78 | + // сбрасываем «все» таймауты |
| 79 | + var biggestTimeoutId = window.setTimeout(function(){}, 1), |
| 80 | + i; |
| 81 | + for(i = 1; i <= biggestTimeoutId; i++) { |
| 82 | + clearTimeout(i); |
| 83 | + } |
| 84 | + |
| 85 | +Однако, даже при том, что такой код работает сегодня во всех современных браузерах, нигде не указано и не гарантируется, что значения ID всегда увеличиваются. Поэтому, всё же, рекомендуется следить за *каждым* идентификатором *каждого* создающегося таймаута — это позволит вам надёжно контролировать процесс, сбрасывая их индивидуально. |
73 | 86 |
|
74 | 87 | ### Скрытое использование `eval`
|
75 | 88 |
|
76 |
| -`setTimeout` и `setInterval` могут принимать строку в качестве первого параметра. Эту возможность не следует использовать **никогда**, поскольку изнутри при этом производится скрытый вызов `eval`. |
| 89 | +`setTimeout` и `setInterval` могут принимать строку в качестве первого параметра. Эту возможность не стоит использовать **никогда**, поскольку изнутри, при этом, производится скрытый вызов `eval`. |
77 | 90 |
|
78 | 91 | > **Замечание**: Поскольку функции работы с таймаутами **не** определены в стандарте ECMAScript, точная внутренняя механика их работы может различаться от движка к движку. Например, Microsoft JScript использует конструктор `Function` вместо `eval`.
|
79 | 92 |
|
|
89 | 102 | }
|
90 | 103 | bar();
|
91 | 104 |
|
92 |
| -Поскольку `eval` в этом случае не вызывается [напрямую](#core.eval), переданная в `setTimeout` строка будет выполнена в *глобальной области видимости*; так что локальная переменная `foo` из области видимости `bar` не будет выполнена. |
| 105 | +Поскольку `eval` в этом случае не вызывается [явно](#core.eval), переданная в `setTimeout` строка будет выполнена в *глобальной области видимости*; так что локальная функция `foo` из области видимости `bar` вообще не будет выполнена. |
93 | 106 |
|
94 |
| -По этим же причинам рекомендуется **не** использовать строку для передачи аргументов в функцию, которая должна быть вызвана из одной из двух функций, работающих с таймаутами. |
| 107 | +По этим же причинам **не рекомендуется** использовать строковое представление вызова функции для передачи аргументов в функцию, которая должна быть вызвана посредством любого из двух известных способов назначения таймаутов. |
95 | 108 |
|
96 | 109 | function foo(a, b, c) {}
|
97 | 110 |
|
|
103 | 116 | foo(a, b, c);
|
104 | 117 | }, 1000)
|
105 | 118 |
|
106 |
| -> **Замечание:** При том, что синтаксис `setTimeout(foo, 1000, a, b, c)` разрешено использовать, это крайне не рекомендуется, поскольку может привести к сложно-разпознаваемым ошибкам при работе с [методами](#function.this). |
| 119 | +> **Замечание:** При том, что практически возможно использовать синтаксис `setTimeout(foo, 1000, a, b, c)`, делать это крайне не рекомендуется, поскольку может привести к трудно-отлавливаемым ошибкам при операциях с [методами](#function.this). |
107 | 120 |
|
108 | 121 | ### Заключение
|
109 | 122 |
|
110 |
| -**Никогда** не используйте строки как параметры `setTimeout` или `setInterval`. Это явный признак **действительно** плохого кода. Если вызываемой функции необходимо передавать аргументы, лучше передавать *анонимную функцию*, которая самостоятельно будет отвечать за сам вызов. |
| 123 | +**Никогда** не используйте строки как параметры для `setTimeout` или `setInterval`. Это явный признак **действительно** плохого кода. Если вызываемой функции необходимо передавать аргументы, лучше передавать *анонимную функцию*, которая самостоятельно будет отвечать за сам вызов. |
111 | 124 |
|
112 |
| -Кроме того, избегайте использования `setInterval` в случаях, когда его планировщик может блокировать выполнение JavaScript. |
| 125 | +Кроме прочего, избегайте использования `setInterval` в случаях, когда его планировщик может заблокировать выполнение основного кода JavaScript. |
113 | 126 |
|
114 | 127 | [1]: http://ru.wikipedia.org/wiki/Document_Object_Model "Document Object Model"
|
115 | 128 |
|
0 commit comments