1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
---
title: WindowOrWorkerGlobalScope.setTimeout()
slug: Web/API/setTimeout
tags:
- API
- HTML DOM
- Méthode
- Reference
translation_of: Web/API/WindowOrWorkerGlobalScope/setTimeout
original_slug: Web/API/WindowOrWorkerGlobalScope/setTimeout
---
<div>{{APIRef("HTML DOM")}}</div>
<p>La méthode <strong><code>setTimeout()</code></strong>, rattachée au <em>mixin</em> {{domxref("WindowOrWorkerGlobalScope")}} (et qui succède à <code>window.setTimeout()</code>) permet de définir un « minuteur » (<em>timer</em>) qui exécute une fonction ou un code donné après la fin du délai indiqué.</p>
<h2 id="Syntaxe">Syntaxe</h2>
<pre class="syntaxbox"><em>var identifiant</em> = <em>scope</em>.setTimeout(<em>fonction</em>[, <em>delai</em>, <em>param1</em>, <em>param2</em>, ...]);
<em>var</em> <em>identifiant</em> = <em>scope</em>.setTimeout(<em>fonction</em>[, <em>delai</em>]);
<em>var identifiant</em> = <em>scope</em>.setTimeout(<em>code</em>[, <em>delai</em>]);
</pre>
<h3 id="Paramètres">Paramètres</h3>
<dl>
<dt><code>function</code></dt>
<dd>Une fonction ({{jsxref("function")}}) qui doit être exécuté au déclenchement du minuteur après le temps imparti.</dd>
<dt><code>code</code></dt>
<dd>Une chaîne de caractères qui représente le code à exécuter. Cette chaîne est compilée et exécutée à l'expiration du minuteur. Pour des raisons analogues à celles exprimées avec {{jsxref("Objets_globaux/eval", "eval()")}}, cette syntaxe n'est pas <strong>recommandée</strong>.</dd>
<dt><code>delai</code> {{optional_inline}}</dt>
<dd>La durée, exprimée en millisecondes, à attendre avant que la fonction indiquée soit exécutée. Par défaut, ce paramètre vaut 0, ce qui signifiie que la fonction est exécutée dès que possible. La durée réelle mesurée avant l'exécution de la fonction peut être supérieure à ce paramètre, voir <a href="#durée">la section ci-après</a>.</dd>
<dt><code>param1, … , paramN</code> {{optional_inline}}</dt>
<dd>D'autres paramètres qui seront passés à la fonction une fois que le temps est écoulé.</dd>
</dl>
<div class="note">
<p><strong>Note :</strong> La première syntaxe utilisant les paramètres supplémentaires ne fonctionne pas pour Internet Explorer 9 et les versions antérieures. Si vous souhaitez obtenir cette fonctionnalité pour ce navigateur, vous devrez utiliser une prothèse, <a href="#polyfill">voir ci-après</a>.</p>
</div>
<h3 id="Valeur_de_retour">Valeur de retour</h3>
<p>La valeur renvoyée par la fonction est un entier qui représente un identifiant du minuteur créé par l'appel à <code>setTimeout()</code>. Cet identifiant pourra être passé à la méthode {{domxref("WindowOrWorkerGlobalScope.clearTimeout","clearTimeout()")}} afin d'annuler ce minuteur donné.</p>
<p>Il peut être utile de savoir que <code>setTimeout()</code> et {{domxref("WindowOrWorkerGlobalScope.setInterval", "setInterval()")}} partagent le même ensemble d'identifiants et que <code>clearTimeout()</code> et {{domxref("WindowOrWorkerGlobalScope.clearInterval", "clearInterval()")}} sont, techniquement, interchangeables. Toutefois pour des raisons de lisibilité et de maintenance, mieux vaut les utiliser par paires plutôt que de les mélanger.</p>
<p>Le moteur d'exécution garantit qu'un identifiant donné ne sera pas réutilisé par un appel ultérieur à <code>setTimeout()</code> ou <code>setInterval()</code> pour un même objet (une fenêtre ou un <em>worker</em>). En revanche, différents objets possèdent chacun leurs ensembles d'identifiants.</p>
<h2 id="Exemples">Exemples</h2>
<p>Dans l'exemple qui suit, on dispose deux boutons classiques auxquels on associe, via des gestionnaires d'évènements, des fonctions qui utilisent <code>setTimeout()</code> et <code>clearTimeout()</code>. Utiliser le premier bouton déclenchera un minuteur qui affichera une boîte de dialogue après deux secondes. L'identifiant est enregistré à la création du minuteur et on peut annuler le minuteur en cours en appuyant sur le deuxième bouton (dont la fonction associée au gestionnaire d'évènements utilise <code>clearTimeout()</code>).</p>
<h3 id="HTML">HTML</h3>
<pre class="brush: html"><button onclick="delayedAlert();">
Affiche une alerte après deux secondes
</button>
<p></p>
<button onclick="clearAlert();">
Annuler l'alerte avant qu'elle ne se déclenche
</button>
</pre>
<h3 id="JavaScript">JavaScript</h3>
<pre class="brush: js">var timeoutID;
function delayedAlert() {
timeoutID = window.setTimeout(slowAlert, 2000);
}
function slowAlert() {
alert("C'était long…");
}
function clearAlert() {
window.clearTimeout(timeoutID);
}
</pre>
<h3 id="Résultat">Résultat</h3>
<p>{{EmbedLiveSample('Exemples')}}</p>
<div class="note">
<p><strong>Note :</strong> Voir aussi les exemples pour <a href="/fr/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout#Exemples"><code>clearTimeout()</code></a>.</p>
</div>
<h2 id="Prothèse_d'émulation_(polyfill)">Prothèse d'émulation (<em>polyfill</em>)</h2>
<p>S'il vous faut passer un ou plusieurs arguments à la fonction de rappel tout en prenant en charge Internet Explorer 9 et les versions antérieures, vous pouvez utiliser cette prothèse qui ajoute la prise en charge des paramètres additionnels :</p>
<pre class="brush: js">/*\
|*|
|*| Polyfill which enables the passage of arbitrary arguments to the
|*| callback functions of JavaScript timers (HTML5 standard syntax).
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
|*|
\*/
(function() {
setTimeout(function(arg1) {
if (arg1 === 'test') {
// l'argument est passé, pas besoin de prothèse
return;
}
var __nativeST__ = window.setTimeout;
window.setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
var aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeST__(vCallback instanceof Function ? function() {
vCallback.apply(null, aArgs);
} : vCallback, nDelay);
};
}, 0, 'test');
var interval = setInterval(function(arg1) {
clearInterval(interval);
if (arg1 === 'test') {
// l'argument est passé, pas besoin de prothèse
return;
}
var __nativeSI__ = window.setInterval;
window.setInterval = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
var aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeSI__(vCallback instanceof Function ? function() {
vCallback.apply(null, aArgs);
} : vCallback, nDelay);
};
}, 0, 'test');
}())
</pre>
<h3 id="Correctif_ciblé_sur_IE">Correctif ciblé sur IE</h3>
<p>Si vous souhaitez ne cibler que IE 9 et antérieurs, vous pouvez utiliser les commentaires conditionnels JavaScript :</p>
<pre class="brush: js">/*@cc_on
// conditional IE < 9 only fix
@if (@_jscript_version <= 9)
(function(f){
window.setTimeout = f(window.setTimeout);
window.setInterval = f(window.setInterval);
})(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}});
@end
@*/
</pre>
<p>Ou plutôt les commentaires conditionnels HTML :</p>
<pre class="brush: html"><!--[if lte IE 9]><script>
(function(f){
window.setTimeout=f(window.setTimeout);
window.setInterval=f(window.setInterval);
})(function(f){return function(c,t){
var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}
});
</script><![endif]-->
</pre>
<h3 id="Autres_méthodes_de_contournement">Autres méthodes de contournement</h3>
<p>Vous pouvez également utiliser une fonction anonyme comme fonction de rappel (<em>callback</em>) :</p>
<pre class="brush: js">var intervalID = setTimeout(function() {
maFonction('un', 'deux', 'trois');
}, 1000);
</pre>
<p>Voici une réécriture de l'exemple précédent avec <a href="/fr/docs/Web/JavaScript/Reference/Fonctions/Fonctions_fl%C3%A9ch%C3%A9es">les fonctions fléchées</a> :</p>
<pre class="brush: js">var intervalID = setTimeout(() => {
maFonction('un', 'deux', 'trois');
}, 1000);
</pre>
<p>On peut également utiliser {{jsxref("Function.prototype.bind()")}} :</p>
<pre class="brush: js">setTimeout(function(arg1){}.bind(undefined, 10), 1000);
</pre>
<h2 id="Le_problème_«_this_»">Le problème « <code>this</code> »</h2>
<p>Lorsqu'on passe une fonction à <code>setTimeout()</code>, cette fonction peut être appelée avec une valeur <code>this</code> qui n'est pas celle qu'on attend. Ce problème est expliqué en détails dans la référence JavaScript<a href="/fr/docs/Web/JavaScript/Reference/Opérateurs/L_opérateur_this#Dans_le_contexte_d'une_fonction">JavaScript reference</a>.</p>
<h3 id="Explications">Explications</h3>
<p>Le code exécuté par <code>setTimeout()</code> est appelé dans un contexte d'exécution différent de celui de la fonction où <code>setTimeout</code> a été appelé. Les règles usuelles pour la détermination de <code>this</code> s'appliquent : si <code>this</code> n'est pas défini lors de l'appel ou avec <code>bind</code>, la valeur par défaut sera l'objet global (<code>global</code> ou <code>window</code>) en mode non-strict ou {{jsxref("undefined")}} en mode strict. Aussi, le <code>this</code> utilisé par la fonction de rappel ne sera pas le même <code>this</code> que celui utilisé par la fonction ayant appelé <code>setTimeout</code>.</p>
<div class="note">
<p><strong>Note :</strong> La valeur par défaut pour <code>this</code>, lors de l'utilisation d'une fonction de rappel par <code>setTimeout</code> sera toujours l'objet <code>window</code> et pas la valeur <code>undefined</code>, même en mode strict.</p>
</div>
<p>Par exemple :</p>
<pre class="brush: js">monTableau = ['zéro', 'un', 'deux'];
monTableau.maMéthode = function (sPropriété) {
console.log(arguments.length > 0 ? this[sPropriété] : this);
};
monTableau.maMéthode(); // affichera "zéro,un,deux" dans la console
monTableau.maMéthode(1); // affichera "un"</pre>
<p>Le code qui précède fonctionne car lorsque <code>maMéthode</code> est appelée, <code>this</code> correspond à <code>monTableau</code> et qu'au sein de <code>maMéthode</code>, <code>this[sPropriété]</code> correspond alors à <code>monTableau[sPropriété]</code>. Toutefois, avec :</p>
<pre class="brush: js">setTimeout(monTableau.maMéthode, 1000);
// affiche "[object Window]" après 1 seconde
setTimeout(monTableau.maMéthode, 1500, '1');
// affiche "undefined" après 1.5 seconde</pre>
<p>La fonction <code>monTableau.maMéthode</code> est pasée à <code>setTimeout</code> et, lorsqu'elle est appelée, <code>this</code> n'est pas défini et le moteur utilise la valeur par défaut : <code>window</code>. Il n'y apas d'option qui permettent de passer une valeur <code>thisArg</code> à <code>setTimeout()</code> comme on peut le faire avec {{jsxref("Array.prototype.forEach()")}} ou {{jsxref("Array.prototype.reduce()")}} par exemple. Aussi, utiliser <code>call()</code> afin de définir <code>this</code> ne fonctionnera pas non plus.</p>
<pre class="brush: js">setTimeout.call(monTableau, monTableau.maMéthode, 2000);
// error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(monTableau, monTableau.maMéthode, 2500, 2);
// même erreur
</pre>
<h3 id="Solutions_éventuelles">Solutions éventuelles</h3>
<div class="note">
<p><strong>Note :</strong> JavaScript 1.8.5 introduced the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">Function.prototype.bind()</a></code> method to set the value of <code>this</code> for all calls to a given function. This can avoid having to use a wrapper function to set the value of <code>this</code> in a callback.</p>
</div>
<p>Exemple d'utilisation :</p>
<pre class="brush: js">var monTableau = ['zéro', 'un', 'deux'];
var maMéthodeLiée = (function (sPropriété) {
console.log(arguments.length > 0 ? this[sPropriété] : this);
}).bind(monTableau);
maMéthodeLiée(); // affiche "zéro,un,deux"
maMéthodeLiée(1); // affiche "un"
setTimeout(maMéthodeLiée, 1000);
// affiche "zéro,un,deux" après une seconde
setTimeout(maMéthodeLiée, 1500, "1");
// affiche "un" après 1.5 seconde
</pre>
<h2 id="Notes">Notes</h2>
<p>Les minuteurs peuvent être annulés avec {{domxref("WindowOrWorkerGlobalScope.clearTimeout","clearTimeout()")}}. Si on souhaite appeler une fonction de façon répétée, on utilisera plutôt {{domxref("WindowOrWorkerGlobalScope.setInterval()","setInterval()")}}.</p>
<h3 id="Utiliser_des_chaînes_pour_le_code_plutôt_que_des_fonctions">Utiliser des chaînes pour le code plutôt que des fonctions</h3>
<p>Passer une chaîne de caractères pour le code à exécuter, plutôt qu'une fonction, souffre des mêmes dangers que {{jsxref("Objets_globaux/eval","eval()")}}.</p>
<pre class="brush: js">// Recommandé
window.setTimeout(function() {
console.log('Coucou monde !');
}, 500);
// Non recommandé
window.setTimeout("console.log('Coucou monde !');", 500);
</pre>
<p>Une chaîne de caractères passée à <code>setTimeout</code> sera évaluée dans le contexte global. Aussi, les symboles locaux au contexte de l'appel de <code>setTimeout()</code> ne seront pas accessibles au code présent dans la chaîne de caractères lors de son évaluation.</p>
<h3 id="Durée_plus_longue_que_le_paramètre_indiquée">Durée plus longue que le paramètre indiquée</h3>
<p>Plusieurs raisons peuvent expliquer une durée réelle plus longue que le délai passé en argument. Voici les plus fréquentes.</p>
<h4 id="Précision_minimale_à_4ms">Précision minimale à 4ms</h4>
<p>Dans les navigateurs récents les appels à <code>setTimeout()/</code>{{domxref("WindowOrworkerGlobalScope.setInterval","setInterval()")}} possèdent au plus une précision de 4ms lorsque plusieurs appels imbriqués sont réalisés. Par exemple :</p>
<pre class="brush: js">function cb() { f(); setTimeout(cb, 0); }
setTimeout(cb, 0);</pre>
<pre class="brush: js">setInterval(f, 0);</pre>
<p>Pour Chrome et Firefox, la limitation est active à partir du cinquième appel de fonction de rappel, Safari active la limitation à partir du sixième et Edge à partir du troisième. Gecko traite <code>setInterval()</code> de la même façon depuis la <a href="/fr/docs/Mozilla/Firefox/Releases/56">version 56</a>.</p>
<p><a href="http://code.google.com/p/chromium/issues/detail?id=792#c10">Par le passé</a>, certains navigateurs implémentaient cette limite différemment (pour les appels à <code>setInterval()</code> quelle que soit leur provenance ou lorsqu'un appel <code>setTimeout()</code> était imbriqué dans un autre pour un certain nombre de niveaux d'imbrication.</p>
<p>Pour implémenter un minuteur de 0ms, on pourra utiliser {{domxref("window.postMessage()")}}.</p>
<div class="note">
<p><strong>Note :</strong> Le délai minimal est géré dans Firefox via une préférence : <code>dom.min_timeout_value</code>.</p>
</div>
<div class="note">
<p><strong>Note :</strong> Cette durée de 4 ms est <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers">définie dans la spécification HTML5</a> et est la même dans l'ensemble des navigateurs à partir de 2010. Avant {{geckoRelease("5.0")}}, la valeur minimale pour les appels imbriqués était 10ms.</p>
</div>
<h4 id="Précision_minimale_des_minuteurs_pour_les_onglets_inactifs_plus_de_1000ms">Précision minimale des minuteurs pour les onglets inactifs : plus de 1000ms</h4>
<p>Afin de réduire la charge (ainsi que la consommation d'énergie associée) des onglets en arrière-plan, les minuteurs ne sont déclenchés au maximum qu'une fois par seconde pour les onglets inactifs.</p>
<p>Firefox implémente ce comportement depuis Firefox 5 (cf. {{bug(633421)}}) et la valeur du seuil de 1000ms peut être paramétrée via la préférence <code>dom.min_background_timeout_value</code>. Chrome implémente ce comportement depuis la version 11 (<a href="http://crbug.com/66078">crbug.com/66078</a>).</p>
<p>Firefox pour Android utilise un minimum de 15 minutes depuis Firefox 14 (cf. {{bug(736602)}}) et les onglets en arrière-plan peuvent être déchargés complètement.</p>
<div class="note">
<p><strong>Note :</strong> Firefox 50 ne limite plus la réactivité des onglets en arrière-plan si un contexte Web Audio API {{domxref("AudioContext")}} joue un son. Firefox 51 élargit le spectre en supprimant la limitation si un objet {{domxref("AudioContext")}} est présent dans l'onglet, même sans jouer de son. Cela a permis de résoudre différents problèmes avec certaines applications qui jouent de la musique en arrière-plan.</p>
</div>
<h4 id="Limitation_des_minuteurs_pour_les_scripts_de_pistage">Limitation des minuteurs pour les scripts de pistage</h4>
<p>Depuis Firefox 55, les scripts de pistage (par exemple Google Analytics) (c'est-à-dire que toute URL que Firefox reconnaît comme appartenant à un domaine de pistage via <a href="https://wiki.mozilla.org/Security/Tracking_protection#Lists">la liste TP</a>) ont une limitation plus forte. En premier plan la limitation est toujours de 4ms mais pour les onglets en arrière-plan, la limite est à 10000ms une fois que 30 secondes se sont écoulées après le premier chargement du document.</p>
<p>Ces seuils peuvent être gérés via les préférences :</p>
<ul>
<li><code>dom.min_tracking_timeout_value</code> : 4</li>
<li><code>dom.min_tracking_background_timeout_value</code> : 10000</li>
<li><code>dom.timeout.tracking_throttling_delay</code> : 30000</li>
</ul>
<h4 id="Minuteurs_en_retard">Minuteurs en retard</h4>
<p>En plus de ces limitations, le minuteur peut être déclenché plus tard si le navigateur ou le système d'opération est occupé sur d'autres tâches. On notera particulièrement que la fonction de rappel n'est pas exécutée tant que le <em>thread</em> du script n'a pas terminé. Par exemple :</p>
<pre class="brush: js">function toto() {
console.log('appel de toto');
}
setTimeout(toto, 0);
console.log('Après setTimeout');</pre>
<p>affichera, dans la console :</p>
<pre class="brush: js">Après setTimeout
appel de toto</pre>
<p>Ici, même si <code>setTimeout</code> a été appelé avec un délai nul, la fonction de rappel est placée dans la queue et est planifiée pour être exécutée dès que possible : ce qui n'est pas « immédiatement ». Le code courant doit finir d'être exécuté afin que les appels dans la queue puissent être dépilés.</p>
<h3 id="Valeur_de_délai_maximale">Valeur de délai maximale</h3>
<p>Les navigateurs que sont Internet Explorer, Chrome, Safari et Firefox stockent, en interne, la valeur du délai comme un entier sur 32 bits signé. Il y a donc un dépassement de borne si le délai est supérieur à 2147483647 millisecondes, ce qui correspond à 24.8 days. Si une telle valeur (supérieure à ce seuil) est utilisée, le minuteur est déclenché dès que possible.</p>
<h2 id="Spécifications">Spécifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th>Spécification</th>
<th>État</th>
<th>Commentaires</th>
</tr>
<tr>
<td>{{SpecName('HTML WHATWG', 'webappapis.html#dom-settimeout', 'WindowOrWorkerGlobalScope.setTimeout()')}}</td>
<td>{{Spec2("HTML WHATWG")}}</td>
<td>Déplacement de la méthode sur le <em>mixin</em> <code>WindowOrWorkerGlobalScope</code> dans la dernière spécification.</td>
</tr>
<tr>
<td>{{SpecName("HTML WHATWG", "webappapis.html#dom-settimeout", "WindowTimers.setTimeout()")}}</td>
<td>{{Spec2("HTML WHATWG")}}</td>
<td>Définition initiale (<em>DOM Level 0</em>)</td>
</tr>
</tbody>
</table>
<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2>
<p>{{Compat("api.WindowOrWorkerGlobalScope.setTimeout")}}</p>
<h2 id="Voir_aussi">Voir aussi</h2>
<ul>
<li>{{domxref("WindowOrWorkerGlobalScope.clearTimeout")}}</li>
<li>{{domxref("WindowOrWorkerGlobalScope.setInterval")}}</li>
<li>{{domxref("window.requestAnimationFrame")}}</li>
</ul>
|