Chiamare funzioni con setTimeout ()

In poche parole …

perché lo fa

setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay); 

funziona perfettamente, chiamando la funzione dopo il ritardo specificato, ma

 setTimeout(playNote(currentaudio.id,noteTime), delay); 

chiama la funzione playNota tutto allo stesso tempo?

(questi setTimeout () s sono in un ciclo for)

o, se la mia spiegazione è troppo difficile da leggere, qual è la differenza tra le due funzioni?

Il primo modulo che elencate funziona, dal momento che valuterà una stringa alla fine del delay . L’uso di eval() è generalmente una buona idea, quindi dovresti evitare questo.

Il secondo metodo non funziona, poiché si esegue immediatamente un object funzione con la funzione call operator () . Quello che succede è che playNote viene eseguito immediatamente se si utilizza il form playNote(...) , quindi non accadrà nulla alla fine del ritardo.

Invece, devi passare una funzione anonima per impostare Timeout, quindi il modulo corretto è:

 setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay); 

Si noti che si passa setTimeout un’intera espressione di funzione, in modo da conservare la funzione anonima e solo eseguirla alla fine del ritardo.

È anche ansible passare setTimeout un riferimento, poiché un riferimento non viene eseguito immediatamente, ma non è ansible passare argomenti:

 setTimeout(playNote, delay); 

Nota:

Per eventi ripetuti è ansible utilizzare setInterval() ed è ansible impostare setInterval() su una variabile e utilizzare la variabile per interrompere l’intervallo con clearInterval() .

Tu dici di usare setTimeout() in un ciclo for . In molte situazioni, è meglio usare setTimeout() in una funzione ricorsiva. Questo perché in un ciclo for , le variabili utilizzate nel setTimeout() non saranno le variabili come erano quando setTimeout() iniziato, ma le variabili così come sono dopo il ritardo quando la funzione viene triggersta.

Basta usare una funzione ricorsiva per eludere l’intero problema.

Utilizzo della ricorsione per gestire i tempi di ritardo variabili:

  // Set original delay var delay = 500; // Call the function for the first time, to begin the recursion. playNote(xxx, yyy); // The recursive function function playNote(theId, theTime) { // Do whatever has to be done // ... // Have the function call itself again after a delay, if necessary // you can modify the arguments that you use here. As an // example I add 20 to theTime each time. You can also modify // the delay. I add 1/2 a second to the delay each time as an example. // You can use a condition to continue or stop the recursion delay += 500; if (condition) { setTimeout(function() { playNote(theID, theTime + 20) }, delay); } } 

Prova questo.

 setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay); 

Non usare stringhe timeout. È efficace una eval , che è una brutta cosa. Funziona perché sta convertendo noteTime e noteTime alle rappresentazioni di stringa di se stessi e nascondendole nel codice. Funziona solo finché quei valori hanno toString() che generano la syntax JavaScript letterale che ricrea il valore, che è vero per Number ma non per molto altro.

 setTimeout(playNote(currentaudio.id, noteTime), delay); 

questa è una chiamata di funzione. playNote viene chiamato immediatamente e il risultato restituito dalla funzione (probabilmente undefined ) viene passato a setTimeout() , non ciò che si desidera.

Come menzionano altre risposte, puoi usare un’espressione di funzione inline con una chiusura per fare riferimento a noteTime e noteTime :

 setTimeout(function() { playNote(currentaudio.id, noteTime); }, delay); 

Tuttavia, se sei in un loop e noteTime o noteTime è diverso ogni volta nel ciclo, hai il Problema Loop Closure: la stessa variabile sarà referenziata in ogni timeout, quindi quando vengono chiamati otterrai lo stesso valore ogni volta, il valore che era rimasto nella variabile quando il ciclo terminava prima.

Puoi aggirare questo problema con un’altra chiusura, prendendo una copia del valore della variabile per ogni iterazione del ciclo:

 setTimeout(function() { return function(currentaudio, noteTime) { playNote(currentaudio.id, noteTime); }; }(currentaudio, noteTime), delay); 

ma ora sta diventando un po ‘brutto. Migliore è la Function#bind , che applicherà parzialmente una funzione per te:

 setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay); 

(la window serve per impostare il valore di this all’interno della funzione, che è una funzione di bind() che non è necessario qui.)

Tuttavia questa è una funzione della quinta edizione di ECMAScript che non tutti i browser supportano ancora. Quindi se vuoi usarlo devi prima hackerare il supporto, ad es .:

 // Make ECMA262-5 Function#bind work on older browsers // if (!('bind' in Function.prototype)) { Function.prototype.bind= function(owner) { var that= this; if (arguments.length< =1) { return function() { return that.apply(owner, arguments); }; } else { var args= Array.prototype.slice.call(arguments, 1); return function() { return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments))); }; } }; } 

Perché il secondo ti dice di chiamare prima la funzione playNote e poi passare il valore di ritorno da esso a setTimeout.

Ho letteralmente creato un account su questo sito per commentare la risposta di Peter Ajtai (attualmente votata più alta), solo per scoprire che hai bisogno di 50 rep (qualunque cosa sia) per commentare, quindi lo farò come risposta dato che probabilmente vale la pena puntare fuori un paio di cose.

Nella sua risposta, afferma quanto segue:

È anche ansible passare setTimeout un riferimento, poiché un riferimento non viene eseguito immediatamente, ma non è ansible passare argomenti:

 setTimeout(playNote, delay); 

Questo non è vero. Dopo aver setTimeout a setTimeout un riferimento di funzione e una quantità di ritardo, eventuali argomenti aggiuntivi vengono analizzati come argomenti per la funzione di riferimento. Il di sotto sarebbe meglio che avvolgere una chiamata di funzione in una funzione.

 setTimeout(playNote, delay, currentaudio.id, noteTime) 

Consulta sempre i documenti.

Detto questo, come sottolinea Peter, una funzione ricorsiva sarebbe una buona idea se si desidera variare il ritardo tra ogni playNote() , o considerare l’utilizzo di setInterval() se si desidera che ci sia lo stesso ritardo tra ogni playNote() .

Vale anche la pena notare che se si desidera analizzare l’ i del proprio ciclo for in un setTimeout() , è necessario includerlo in una funzione, come descritto qui.