javascript - recursivos - Promesas de encadenamiento recursivamente
recursividad en typescript (4)
Bueno, resolví mi problema; mi función recursiva fue malinterpretar los datos y por lo tanto nunca dejó de repetirse. Gracias por su ayuda, y me aseguraré de ver esos screencasts, ya que todavía no entiendo completamente la estructura de encadenamiento Promise.
Estoy trabajando en una aplicación simple de Windows 8 en la que necesito obtener un conjunto de datos de un sitio web. Estoy usando WinJS.xhr () para recuperar estos datos, que devuelve una Promesa. Luego paso una devolución de llamada al método .then () de esta Promesa, que proporciona a mi devolución de llamada el valor devuelto de la llamada asíncrona. El método .then () devuelve otra Promesa, dándole el valor que devuelve mi devolución de llamada. La estructura básica de dicha consulta sería la siguiente:
WinJS.xhr({ url: "http://www.example.com/" }).then(
function callback( result_from_xhr )
{
//do stuff
return some_value;
}).then(
function secondcallback( some_value )
{
//do stuff
});
Sin embargo, en mi situación, es posible que tenga que realizar consultas adicionales para los datos en función de los datos devueltos por la primera consulta, y posiblemente más consultas en función de ESOS datos ... y así sucesivamente, recursivamente.
Necesito una forma de codificar esto de tal manera que el .then () final no se ejecute hasta que TODAS las recursiones se hayan completado, de manera similar a esto:
function recurse() {
return WinJS.xhr({ url: "http://www.example.com/" }).then(
function callback( result_from_xhr )
{
if( result_from_xhr == something )
{
recurse();
}
});
}
recurse().then(
function final()
{
//finishing code
});
El problema es que, por supuesto, el código de terminación se llama tan pronto como se completa el primer nivel de recursión. Necesito alguna forma de anidar la nueva promesa y la antigua promesa desde dentro de la devolución de llamada.
Espero que mi pregunta sea lo suficientemente clara, no estoy seguro de cómo explicarlo y, francamente, la idea de un código recursivo asíncrono me duele la cabeza.
Deberá usar el patrón Promise.join (). Done (). Pase una serie de Promesas a unirse (), que en su caso sería una colección de llamadas xhr. La unión () solo llamará a done () cuando todas las Promesas xhr se hayan completado. Obtendrá una serie de resultados pasados a done (), que luego puede repetir y comenzar de nuevo con una nueva llamada Promise.join (). Done (). Lo que hay que evitar, al utilizar este enfoque, es que si una de las Promesas pasadas a join () falla, toda la operación se trata como una condición de error.
Lo siento, no tengo tiempo ahora mismo para intentar tachar el código para ti. Si tengo la oportunidad, lo intentaré más tarde. Pero debería poder insertar esto en su función recursiva y hacer que las cosas funcionen.
Lo que haría aquí es crear una promesa completamente nueva e independiente que puede completar manualmente y devolverla desde la función recurse (). Luego, cuando llegue al punto en que sabe que ha terminado de hacer un trabajo asíncrono, complete esa promesa.
Promise.join funciona cuando tienes un conjunto conocido de promesas: necesitas toda la gama de promesas disponibles antes de llamar para unirte. Si seguí la pregunta original, tienes un número variable de promesas, con más posibilidades de aparecer como parte de un trabajo asíncrono. Unirse no es la herramienta adecuada en estas circunstancias.
Entonces, ¿cómo se ve esto? Algo como esto:
function doSomethingAsync() {
return new WinJS.Promise(function (resolve, reject) {
function recurse() {
WinJS.xhr({ url: "http://www.example.com/" })
.then(function onResult(result_from_xhr) {
if (result_from_xhr === something) {
recurse();
} else {
// Done with processing, trigger the final promise
resolve(whateverValue);
},
function onError(err) {
// Fail everything if one of the requests fails, may not be
// the right thing depending on your requirements
reject(err);
});
}
// Kick off the async work
recurse();
});
}
doSomethingAsync().then(
function final()
{
//finishing code
});
Reorganicé donde está ocurriendo la recursión para que no volvamos a crear una nueva promesa cada vez, por lo que la función recurse () anidada en lugar de tenerla en el nivel externo.
Resolví este problema de una manera quizás diferente (creo que es el mismo problema) al crear mi propia aplicación de Windows 8.
La razón por la que encontré este problema es porque, de manera predeterminada, una consulta a una tabla paginará, y solo devolverá 50 resultados a la vez, así que creé un patrón para obtener los primeros 50, y luego los siguientes 50, etc, hasta una respuesta regresa con menos de 50 resultados y luego resuelve la promesa.
Este código no será real, solo para ilustración:
function getAllRows() {
return new WinJS.Promise(function(resolve, reject){
var rows = [];
var recursivelyGetRows = function(skipRows) {
table.skip(skipRows).read()
.then(function(results){
rows = rows.concat(results);
if (results.length < 50) {
resolve(rows);
} else {
recursivelyGetRows(skipRows + 50);
}
})
}
recursivelyGetRows(0);
});
}
así que getAllRows () devuelve una promesa que se resuelve solo después de que obtengamos un resultado con menos de 50 resultados (lo que indica que es la última página).
Dependiendo de su caso de uso, probablemente querrá lanzar un manejador de errores allí también.
En caso de que no esté claro, ''tabla'' es una tabla de servicios móviles.