2011-11-26 26 views
6

Ho una funzione asincrona che desidero avere un ritardo di 5000 ms prima di essere attivata. Sto cercando di usare setTimeout() per raggiungere questo obiettivo. Questa funzione asincrona si verifica in un ciclo che viene eseguito più volte, con la funzione asincrona che riceve ogni volta dati diversi, pertanto non è possibile utilizzare setInterval() qui.setTimeout su Funzione asincrona

Problema: La funzione asincrono viene attivato immediatamente senza ritardo (stampe console 5 Done messaggi instantly` e loop senza alcun ritardo Che cosa è successo e come posso risolverlo

codice JavaScript

.?
someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     setTimeout(asyncFunction(listing, function(data) { 
      console.log('Done'); 
     }), 5000); 
    } 
}); 
+0

Se "elenchi" è in realtà un array, non si deve ripetere "per ... in". Utilizzare invece un indice numerico. – Pointy

+0

@Pointy Sì, è solo un array, oops :) – Nyxynyx

risposta

9

dovete avvolgere la funzione in un'altra funzione. Attualmente, si sta invocando la funzione, e passando il valore restituito come argomento di setTimeout. il codice qui sotto (Cor tly) passare una funzione a setTimeout. Dopo 5 secondi, la funzione viene eseguita.

Ho dovuto aggiungere due funzioni per ottenere il comportamento desiderato, a causa di problemi di ambito. Dopo 5 secondi, il ciclo è già terminato e la variabile listing sarà uguale all'ultimo elemento in listings.

someFunction(listings, function() { 
    var counter = 0; // Define counter for 5 second-delays between each call 
    for (var i in listings) { 
     var listing = listings[i]; 
     (function(listing){ //Closure function 
      setTimeout(function(){ //setTimeout function 
       // Because of the closure, `listing` is unique 
       asyncFunction(listing, function(a, b) { 
        console.log('Done'); 
       }); 
      }, 5000 * ++counter); //Increase counter for each loop 
     })(listing); 
    } 
}); 
+0

questo causerà comunque n timeout quasi paralleli. – jAndy

+0

Grazie per la risposta! C'è un ritardo iniziale di 5000 ms, ma le chiamate successive alla funzione async si verificano immediatamente! Le chiamate successive alle funzioni possono avere ritardi tali che ogni chiamata è distante 5000ms? – Nyxynyx

+0

ha anche il classico problema di loop/scope (la variabile "listing") – Pointy

-1

è il difference.the punto chiave è che cosa è asyncFunction fare? puoi incollarlo?

var foo=function(){ 
    alert("BAR"); 
    return function(){ 
     alert("I AM!"); 
    }; 
} 
setTimeout(foo(),4000); 
setTimeout(foo,5000); 
+4

Il primo "setTimeout()" non è corretto, poiché invocherà immediatamente "foo()" e passerà il suo * risultato * a "setTimeout()". Il secondo, passando una stringa, è generalmente considerato deprecato. – Pointy

+0

sì, la stringa che passa lo renderà "eval" e quindi lo eseguirà su scala globale. Pessima idea – Rifat

+0

grazie mille! – island205

1

Non sapendo che cosa il vostro asyncFunction fa, sembrerebbe che potrebbe semplicemente restituire la funzione che si passò.

someFunction(listings, function() { 
    for (var i = 0; i < listings.length; ++i) { 
     setTimeout(asyncFunction(listings[i], function(data) { 
      console.log('Done'); 
     }), 5000 * i); 
    } 
}); 

function asyncFunction(lstng, func) { 
    return func; 
} 

Anche se mi aspetto che è necessario concludere una logica aggiuntiva.

function asyncFunction(lstng, func) { 
    return function() { 
     // do some stuff with the listing 

     // then invoke the func 
     func(); 
    } 
} 

ora i tuoi asyncFunction avvolge tutto ciò che è necessario in una nuova funzione che viene restituito al setTimeout. La nuova funzione richiama anche il callback che hai passato.


JSFIDDLE DEMO

+0

Grazie, ridotto una riga di codice usando 'i' invece di' counter'. asyncFunction utilizza 2 valori di callback all'interno di 'data' e li invia a un altro server. – Nyxynyx

+0

@Nyxynyx: Non sei completamente sicuro di cosa intendi, ma puoi passare tutto ciò che ti serve alla funzione callback. Il mio punto principale era che hai già una funzione con nome, quindi non è necessario aggiungere due livelli di scope inline. Devi solo modificare 'asyncFunction' in modo che * restituisca * una funzione che deve essere invocata da' setTimeout'. Questo è un approccio più pulito. – RightSaidFred

4

Se si utilizza ECMAScript6 è possibile utilizzare Promise.

Quindi creare una funzione di ritardo che avvolgono la chiamata al setTimeout in una promessa:

function delay(ms) { 
    return new Promise(function (resolve) { return setTimeout(resolve, ms); }); 
}; 

e si può usare in quel modo:

someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     delay(5000).then(() => { 
      return asyncFunction(listing); 
     }).then(() => { 
      console.log('Done'); 
     }); 
    } 
}); 

Se si utilizza ECMAScript 2017 è possibile utilizzare aync/await.

Le funzioni asincrone restituiscono la promessa in modo da non dover modificare il codice della funzione di ritardo.

async someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     await delay(5000); 
     await asyncFunction(listing); 
     console.log('Done'); 
    } 
}); 
Problemi correlati