w3schools trabajar sincronas promises promesas promesa platzi funciones con anidadas javascript promise

trabajar - promises javascript w3schools



Cómo encadenar promesas en rechazo (5)

Escribe una función de búsqueda como la siguiente:

function search(number) { if (number < data.length) { fn(data[number]).then(foundResult) .catch(() => search(number + 1)); } } search(0);

Dada una función, fn , que devuelve una promesa, y una matriz de datos de longitud arbitraria (por ejemplo, data = [''apple'', ''orange'', ''banana'', ...] ) cómo encadena las llamadas de función a cada elemento de la matriz en secuencia, de modo que si fn(data[i]) resuelve, la cadena completa completa y deja de llamar a fn , pero si fn(data[i]) rechaza, la siguiente llamada fn(data[i + 1]) ejecuta ?

Aquí hay un ejemplo de código:

// this could be any function which takes input and returns a promise // one example might be fetch() const fn = datum => new Promise((resolve, reject) => { console.log(`trying ${datum}`); if (Math.random() < 0.25) { resolve(datum); } else { reject(); } }); const foundResult = result => { // result here should be the first value that resolved from fn(), and it // should only be called until the first resolve() console.log(`result = ${result}`); }; // this data can be purely arbitrary length const data = [''apple'', ''orange'', ''banana'', ''pineapple'', ''pear'', ''plum'']; // this is the behavior I''d like to model, only for dynamic data fn(''apple'').then(foundResult) .catch(() => { fn(''orange'').then(foundResult) .catch(() => { fn(''banana'').then(foundResult) .catch(() => { /* ... and so on, and so on ... */ }); }); });

Siento que tal vez haya una solución elegante para este patrón que me estoy perdiendo. El comportamiento es muy similar a Array.some() , pero he salido en Array.some() tratando de jugar con eso.

EDITAR: cambié de datos numéricos a cadenas para enfatizar que la solución no necesita depender de que los datos sean numéricos.

EDIT # 2: solo para aclarar más, fn podría ser cualquier función que acepte entrada y devuelva una promesa. La implementación de fn anterior fue solo para dar un ejemplo completo. En realidad, fn podría ser algo así como una solicitud de API, una consulta de base de datos, etc.


Lo que estás tratando de hacer podría hacerse así, supongo (no es estrictamente equivalente, ver reservas a continuación):

const fn = n => new Promise(() => {}); const seq = []; const process = n => fn(n).then(foundResult); seq.slice(1).reduce((operation, item) => { return operation .catch(() => process(item)); }, process(seq[0]));

Con Promise.race :

const fetchAll = ( urls = [] ) => Promise.race(urls.map(fn)).then(foundResult);

Sin embargo, no estoy seguro de que esto sea lo que intentas lograr: por ejemplo, en tu fragmento no estás devolviendo nada en tu controlador de catch que significa que el foundResult es muy probablemente un efecto secundario. Además, cuando lee su fragmento de código, está detectando errores que pueden surgir desde el resultado de foundResult y no desde la función fn .

Como regla general, siempre intento cumplir mis promesas con un "tipo" conocido o rechazado con un error. No está claro en su ejemplo que la promesa que está generando se liquidará con cualquier valor, ya sea un valor de rejectionValue o un valor de fulfillmentValue .

Tal vez si me proporcionas un caso de uso, podría ayudarte un poco.


Podría escribir una función recursiva muy simple que se detendrá en la primera resolución y recurse en la captura.

function find_it(arr) { let [head, ...rest] = arr if (!head) return console.log("not found") // all rejects or no data fn(head) .then(r => foundResult(r) ) .catch(r => find_it(rest)) } find_it(data)

Esto tiene la ventaja de detenerse en el primer partido sin llamar a todos los valores si se encuentra una coincidencia y no preocuparse por la longitud de los data menos que exceda el tamaño de la pila en la recursión. Por supuesto, sería fácil modificar la acción en el caso extremo cuando todas las promesas rechazan hacer algo.

Resultado cuando se encuentra:

$ node ./test
intentando manzana
tratando de naranja
resultado = naranja

y no encontrado:

$ node ./test trying apple
tratando de naranja
tratando de plátano
tratando de piña
tratando de pera
tratando de ciruela
extraviado


Podrías usar async/await y un loop:

async function search() { for (let item of data) { try { return await fn(item); } catch (err) { } } throw Error ("not found"); } search().then(foundResult).catch(console.log);

  • fn puede devolver Promesa (esperado) o simplemente un valor (devuelto)
  • sus data podrían ser una secuencia infinita iterable (generador)
  • en mi opinión, también es fácil de leer y comprender el intento.

aquí está el resultado si la secuencia falla:

trying apple trying orange trying banana trying pineapple trying pear trying plum Error: not found

el soporte para asincrónico es nativo en es2017, pero puede ser transpilado a es3 / es5 con babel o mecanografiado


Puede usar Array.reduce para obtener los datos deseados.

data.reduce((promise, item) => promise.then( (param) => { if (param) return Promise.resolve(param); return fn(item).catch(() => Promise.resolve()); } ), Promise.resolve()) .then(foundResult)

Básicamente pasará el resultado hasta el final una vez que pase. Y si fn falla, pasará la promesa de valor indefinido a la siguiente cadena para activar fn .