Saltar al contenido

¿Cómo esperar a que se resuelva una promesa de JavaScript antes de reanudar la función?

El tutorial o código que encontrarás en este post es la solución más rápida y efectiva que encontramos a tus dudas o dilema.

Solución:

Me pregunto si hay alguna forma de obtener un valor de una Promesa o esperar (bloquear/dormir) hasta que se resuelva, similar a IAsyncResult.WaitHandle.WaitOne() de .NET. Sé que JavaScript es de un solo subproceso, pero espero que eso no signifique que una función no pueda rendir.

La generación actual de Javascript en los navegadores no tiene un wait() o sleep() que permite que otras cosas funcionen. Entonces, simplemente no puedes hacer lo que estás pidiendo. En cambio, tiene operaciones asíncronas que harán lo suyo y luego lo llamarán cuando terminen (como ha estado usando promesas).

Parte de esto se debe a la subproceso único de Javascript. Si el hilo único está girando, entonces ningún otro Javascript puede ejecutarse hasta que termine ese hilo giratorio. ES6 presenta yield y generadores que permitirán algunos trucos cooperativos como ese, pero estamos bastante lejos de poder usarlos en una amplia muestra de navegadores instalados (se pueden usar en algún desarrollo del lado del servidor donde usted controla el motor JS que es siendo utilizado).


La gestión cuidadosa del código basado en promesas puede controlar el orden de ejecución de muchas operaciones asíncronas.

No estoy seguro de entender exactamente qué orden está tratando de lograr en su código, pero podría hacer algo como esto usando su existente kickOff() función, y luego adjuntar un .then() manejador después de llamarlo:

function kickOff() 
  return new Promise(function(resolve, reject) 
    $("#output").append("start");

    setTimeout(function() 
      resolve();
    , 1000);
  ).then(function() 
    $("#output").append(" middle");
    return " end";
  );


kickOff().then(function(result) 
    // use the result here
    $("#output").append(result);
);

Esto devolverá la salida en un orden garantizado, como este:

start
middle
end

Actualización en 2018 (tres años después de que se escribió esta respuesta):

Si transpila su código o ejecuta su código en un entorno que admita funciones de ES7 como async y awaitahora puedes usar await para hacer que su código “aparezca” para esperar el resultado de una promesa. Todavía se está desarrollando con promesas. Todavía no bloquea todo Javascript, pero le permite escribir operaciones secuenciales en una sintaxis más amigable.

En lugar de la forma ES6 de hacer las cosas:

someFunc().then(someFunc2).then(result => 
    // process result here
).catch(err => 
    // process error here
);

Puedes hacerlo:

// returns a promise
async function wrapperFunc() 
    try 
        let r1 = await someFunc();
        let r2 = await someFunc2(r1);
        // now process r2
        return someValue;     // this will be the resolved value of the returned promise
     catch(e) 
        console.log(e);
        throw e;      // let caller know the promise was rejected with this reason
    


wrapperFunc().then(result => 
    // got final result
).catch(err => 
    // got error
);

Si usa ES2016, puede usar async y await y hacer algo como:

(async () => 
  const data = await fetch(url)
  myFunc(data)
())

Si usa ES2015, puede usar Generadores. Si no le gusta la sintaxis, puede abstraerla usando un async función de utilidad como se explica aquí.

Si usa ES5, probablemente querrá una biblioteca como Bluebird para darle más control.

Finalmente, si su tiempo de ejecución es compatible con ES2015, el orden de ejecución ya puede conservarse con paralelismo utilizando Fetch Injection.

Otra opción es usar Promise.all para esperar un array de promesas para resolver y luego actuar en consecuencia.

El código a continuación muestra cómo esperar a que se resuelvan todas las promesas y luego lidiar con los resultados una vez que estén listos (ya que ese parecía ser el objetivo de la pregunta); También con fines ilustrativos, muestra la salida durante la ejecución (el final termina antes que el medio).

function append_output(suffix, value) 
  $("#output_"+suffix).append(value)


function kickOff() 
  let start = new Promise((resolve, reject) => 
    append_output("now", "start")
    resolve("start")
  )
  let middle = new Promise((resolve, reject) => 
    setTimeout(() => 
      append_output("now", " middle")
      resolve(" middle")
    , 1000)
  )
  let end = new Promise((resolve, reject) => 
    append_output("now", " end")
    resolve(" end")
  )

  Promise.all([start, middle, end]).then(results => 
    results.forEach(
      result => append_output("later", result))
  )


kickOff()

Updated during execution: 
Updated after all have completed:

Te mostramos reseñas y puntuaciones

Puedes asistir nuestro cometido añadiendo un comentario y dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *