Tengo una función asíncrona que realiza una llamada a la API. Se pasa a mi setTimeout() de esta forma:
componentDidMount() { this.pollingId = setTimeout(this.someOtherFunc, 2000) } componentWillUnmount() { clearTimeout(this.pollingId)// clears an old polling id initialised in previous polling call } someOtherFunc = async () => { await axios.get('/some/api') clearTimeout(this.pollingId) if (someConditionToContinuePolling) { this.pollingId = setTimeout(this.someOtherFunc, 2000) // this will not return a value and update this.pollingId before reloadFunc is over } }Entonces, en caso de que la solicitud de API tarde más, cuando navego a otra página mientras la solicitud aún se está procesando, componentWillUnmount borra un ID de sondeo anterior, dejando el otro sin borrar. ¿Hay alguna manera de hacer que setTimeout no espere a que finalice la devolución de llamada asíncrona para devolver su identificación?
ACTUALIZACIÓN : no me importa que finalice la solicitud actual, mi problema es que si navego a otra página mientras se procesa la solicitud, componentWillUnmount borra el pollingId anterior, y this.someOtherFunc() sigue llamándose a sí mismo a través de setTimeout() y nunca deja de votar
Como dice mdn sobre el valor de retorno de setTimeout :
El timeoutID devuelto es un valor entero positivo que identifica el temporizador creado por la llamada a setTimeout(). Este valor se puede pasar a
clearTimeout()para cancelar el tiempo de espera.
De modo que puede recopilar todos timeoutID's , colocarlos en una matriz y ejecutar clearTimeout con estos ID. Vamos a crear una matriz que almacenará todos los timeoutID y el código se vería así:
componentDidMount() { this.pollingId = setTimeout(this.reloadFunc, 2000) this.addIdTimeoutIds(this.pollingId) } someOtherFunc = () => { this.pollingId = setTimeout(this.reloadFunc, 2000) this.addIdTimeoutIds(this.pollingId) } componentWillUnmount() { this.timeoutIDs.forEach(timeoutId => clearTimeout(timeoutId) } addIdTimeoutIds = (pollingId) => this.timeoutIDs.push(pollingId)ACTUALIZACIÓN: si desea cancelar su solicitud, puede usar AbortController (gracias especiales a Pilchard ).
Este es un ejemplo de uso con Axios :
const controller = new AbortController(); axios.get('/foo/bar', { signal: controller.signal }).then(function(response) { //... }); // cancel the request controller.abort()Me di cuenta de que el problema raíz no estaba relacionado con la limpieza del pollingId correcto. Se trataba de abortar el nuevo inicio de las llamadas setTimeout dentro de this.someOtherFunc(). Dado que setTimeout() está llamando a la función en la que se encuentra, tuve una situación de llamada de devolución de llamada actual e iniciando nuevo setTimeOut nuevamente dentro de ella.
La respuesta de @pilchard sobre abortar la llamada de función que ya se está ejecutando me ha empujado hacia esta solución. ¡Muchos gracias!
Simplemente agregar una bandera para detener el sondeo funcionó.
componentDidMount() { this.pollingId = setTimeout(this.someOtherFunc, 2000) } componentWillUnmount() { clearTimeout(this.pollingId)// clears an old polling id initialised in previous polling call this.stopPolling = true } someOtherFunc = async () => { await axios.get('/some/api') clearTimeout(this.pollingId) if (someConditionToContinuePolling && !stopPolling) { this.pollingId = setTimeout(this.someOtherFunc, 2000) // this will not return a value and update this.pollingId before reloadFunc is over } }