2011-11-26 40 views
6

Tengo una función asincrónica que quiero tener un retraso de 5000ms antes de disparar. Estoy tratando de usar setTimeout() para lograr esto. Esta función asíncrona se produce en un bucle que se ejecuta varias veces, con la función asíncrona pasando datos diferentes cada vez, por lo tanto, setInterval() no se puede utilizar aquí.setTimeout en la función asíncrona

Problema: La función asíncrono se desencadena al instante sin retardo (impresiones de la consola 5 Done mensajes instantly` y bucles sin demora Lo que pasó, y cómo puedo resolverlo

Código Javascript

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

Si "listing" es realmente una matriz, no debe repetir con "for ... in". Use un índice numérico en su lugar. – Pointy

+0

@Pointy Sí, es solo una matriz, oops :) – Nyxynyx

Respuesta

9

Tiene que ajustar la función en otra función. Actualmente, está invocando la función y pasando el valor de retorno como un argumento al setTimeout. El código siguiente (correc) tly) pasar una función a setTimeout. Después de 5 segundos, la función se ejecuta.

Tuve que agregar dos funciones para lograr el comportamiento deseado, debido a problemas de alcance. Después de 5 segundos, el ciclo ya ha finalizado, y la variable listing sería igual al último elemento en 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

esto todavía desencadenará n tiempos de espera casi paralelos. – jAndy

+0

¡Gracias por la respuesta! Hay una demora inicial de 5000 ms, ¡pero las llamadas subsiguientes a la función async ocurren instantáneamente! ¿Pueden las llamadas posteriores a las funciones tener retrasos de tal manera que cada llamada esté a 5000ms de distancia? – Nyxynyx

+0

también tiene el clásico problema de bucle/alcance (la variable "listado") – Pointy

-1

es la difference.the punto clave es lo que se asyncFunction hacer? ¿Puedes pegarlo?

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

El primer "setTimeout()" es incorrecto, ya que invocará inmediatamente "foo()" y pasará su * resultado * a "setTimeout()". El segundo, pasar una cadena, generalmente se considera obsoleto. – Pointy

+0

sí, pasar la cadena 'eval' y luego ejecutarlo en el alcance global. Muy mala idea – Rifat

+0

muchas gracias! – island205

1

Sin saber lo que su asyncFunction hace, podría parecer que simplemente podría volver a la función que ha pasado él.

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; 
} 

Aunque espero que deba completar alguna lógica adicional.

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

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

ahora su asyncFunction envolturas lo que sea necesario en una nueva función que se devuelve a la setTimeout. La nueva función también invoca la devolución de llamada que aprobó.


JSFIDDLE DEMO

+0

Gracias, redujo una línea de código usando 'i' en vez de' contador'. asyncFunction usa 2 valores de devolución de llamada dentro de 'data' y los envía a otro servidor. – Nyxynyx

+0

@Nyxynyx: No estoy del todo seguro de lo que quiere decir, pero puede pasar lo que necesite a la función de devolución de llamada. Mi punto principal es que ya tiene una función nombrada, por lo que no es necesario agregar dos niveles de alcance en línea. Solo necesita modificar 'asyncFunction' para que * devuelva * una función para ser invocada por' setTimeout'. Este es un enfoque más limpio. – RightSaidFred

4

Si está utilizando ECMAScript6 puede utilizar Promise.

Por lo tanto crear una función de retardo que envuelven la llamada al setTimeout en una promesa:

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

y se puede utilizar de esa manera:

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

Si está utilizando ECMAScript 2017 puede utilizar aync/await.

Las funciones asincrónicas son prometedoras, por lo que no es necesario cambiar el código de la función de retardo.

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