Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_avanzada_javascript:promises

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
informatica:programacion:cursos:programacion_avanzada_javascript:promises [2024/10/30 15:49] – [Recursos] tempwininformatica:programacion:cursos:programacion_avanzada_javascript:promises [2024/10/30 15:52] (actual) – [DEMO: Errores en promises] tempwin
Línea 661: Línea 661:
 </code> </code>
  
 +===== ¿Cómo limitar el tiempo máximo de ejecución de una Promise? =====
 +
 +Si la API que usamos dentro de la //Promise// ofrece algún mecanismo de //timeout//, lo ideal es usarlo, pero si no es el caso (como curiosamente ocurre con ''fetch'') existe un mecanismo muy sencillo para conseguirlo: usar ''Promise.race''. Esta función toma un iterable de //promises// y devuelva otra promesa que se resuelve/rechaza en cuanto una de las promesas del iterable se resuelva o se rechace.
 +
 +Por lo tanto el mecanismo es muy sencillo. Esta función toma una Promise y devuelve otra con un timeout:
 +
 +<code javascript>
 +const TimeoutPromise = (pr, timeout) =>
 +  Promise.race([pr, new Promise((_, rej) =>
 +    setTimeout(rej, timeout)
 +  )]);
 +</code>
 +
 +Su uso es muy sencillo:
 +
 +<code javascript>
 +let pr = fetch('http://slowwly.robertomurray.co.uk/delay/8000/url/http://www.google.co.uk', {mode: 'no-cors'});
 +let tpr = TimeoutPromise(pr, 500)
 +  .then(() => console.log('fetch done'))
 +  .catch(() =>console.log('timeout cancelled'));
 +</code>
 +
 +La //promise// ''pr'' es una promise que tarda 8 segundos en resolverse (es lo que tarda en cargar esa página), pero si ejecutas ese código verás que al cabo de 500ms la promise ''tpr'' es rechazada.
 +
 +Más fácil imposible, ¿verdad?
 +
 +Bien, nada es perfecto: este método cuando se rechaza la promise por el timeout, **el resto de promises internas siguen ejecutándose**. Es decir, en nuestro caso, tpr es rechazada al cabo de 500ms, pero la promise pr se sigue ejecutando durante los 8s (hasta que se completa la petición de red). Por lo tanto **este mecanismo no aborta promises**. Se limita a envolverlas con una promesa que, esta sí, se resuelve/rechaza en un tiempo máximo.
 +
 +Lo ideal sería poder cancelar la promise, pero ECMAScript no ofrece un mecanismo para poder hacerlo, aunque [[https://github.com/tc39/proposal-cancellation|el TC39 está trabajando en ello]].
 +
 +==== "Cancelando" promises ====
 +
 +Existen [[https://medium.com/@benlesh/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082|otras técnicas]], pero si para ti es vital el poder "cancelar promises" aquí tienes un código muy sencillo que permite **interrumpir una promise en cada uno de sus pasos**. Cada uno de esos pasos debe ser a su vez una promise:
 +
 +<code javascript>
 +const token = function() { 
 +  return {
 +    cancel: function () {this.isCancelled = true},
 +    isCancelled: false
 +    }
 +}
 +async function  MultistepPromise (iterf, token)
 +{
 +  for (let f of iterf) {
 +    await f();
 +    if (token.isCancelled)  {
 +      throw 'promise cancelled';
 +    }
 +  }
 +}
 +</code>
 +
 +Bueno, como puedes ver el código es trivial: simplemente itera por el iterable de promises si por alguna razón el token se cancela.
 +
 +Su uso es, de nuevo, muy sencillo:
 +
 +<code javascript>
 +const func = () => fetch(
 +  'http://slowwly.robertomurray.co.uk/delay/3000/url/http://www.google.co.uk',  
 +  {mode: 'no-cors'});
 +const tok = token();
 +const pr = MultistepPromise([func, func, func, func, func, func], tok)
 +  .then(() => console.log('all acceoted'))
 +  .catch((e) => console.log('some error', e));
 +</code>
 +
 +Si una vez ''pr'' se está ejecutando, llamas a ''tok.cancel()'', entonces ''pr'' se cancelará una vez se haya finalizado el paso correspondiente (a medio paso no se puede cancelar).
 +
 +Observa que ''MultistepPromise'' no espera un array de promises, sino simplemente un iterable de promises, por lo que puedes usar otras técnicas tales como un generador para pasarle las promises a ejecutar.
 +
 +Por supuesto, puedes combinar ambas técnicas: es decir, hacer una ''MultistepPromise'', donde cada uno de sus pasos sea ''TimeoutPromise''. De este modo te aseguras que si uno de los pasos excede el tiempo, todo el resto de pasos se cancelan (no se ejecutan).
 ===== Recursos ===== ===== Recursos =====
  
informatica/programacion/cursos/programacion_avanzada_javascript/promises.1730299757.txt.gz · Última modificación: por tempwin