Estoy tratando de escribir mi función Promise.all() . Debería repetir la funcionalidad del método nativo Promise.all() .
Si solo hay promesas en la matriz, el código funciona correctamente, probablemente el problema aparezca si la matriz contiene algo más que una promesa.
Aquí hay un ejemplo de ejecución:
const p1 = Promise.resolve(3); const p2 = 1337; const p3 = new Promise((resolve, reject) => { setTimeout(resolve, 10000, 'foo'); }); promiseAll([p1, p3, p3]).then(values => console.log(values)); // [3, 1337, "foo"]Aquí está mi código:
const promiseAll = promises => new Promise((resolve, reject) => { if (promises.length === 0) { resolve([]); } const results = []; let resolved = 0; promises.forEach(promise => { if (!(promise instanceof Promise)) { Promise.resolve(promise).then(data => results.push(data)); } promise.then(result => { results.push(result); resolved += 1; if (resolved === promises.length) { resolve(results); } }, error => reject(error)); }); });¿Cuál es el problema?
Dos problemas principales con su implementación:
Dentro del método forEach() , tiene una verificación: promise instanceof Promise . Si esta verificación es falsa, llama a Promise.resolve() PERO luego también llama promise.then(...) ; probablemente quisiste llamar al método then() dentro de un bloque else
Promise.all() mantiene el orden; su implementación no. Esto se debe a que simplemente inserta el resultado de la promesa en la matriz de results en el orden en que se resuelven las promesas.
Puede cambiar su implementación como se muestra a continuación para solucionar los problemas mencionados anteriormente:
const promiseAll = promises => { return new Promise((resolve, reject) => { if (promises.length === 0) { resolve([]); return; } const results = []; let resolved = 0; function collectResult(result, index) { results[index] = result; resolved += 1; if (resolved === promises.length) { resolve(results); } } promises.forEach((value, index) => { if ( typeof value === 'object' && 'then' in value && typeof value.then === 'function' ) { value.then(res => collectResult(res, index)).catch(reject); } else { Promise.resolve(value).then(res => collectResult(res, index)); } }); }); };Está creando una nueva promesa con Promise.resolve (promise) pero no cambia la var de promesa original. Hacer
if (!(promise instanceof Promise)) { promise = Promise.resolve(promise); }EDITAR: siguiendo el comentario de @Ivan Kleshnin aquí está la solución paralela de acuerdo con la especificación :
Promise.all = async function (array) { const results = []; parllalLoopFinish = () =>{ return results.length === array.length; } return new Promise((resolve,reject) =>{ for (let index = 0; index < array.length; index++) { const promise = array[index]; if(promise instanceof Promise){ promise.then((value)=>{ results[index]=value; if(parllalLoopFinish()) { resolve(results); } }).catch(reject) } else{ results[index]=promise; } } if(parllalLoopFinish()) { resolve(results); } }); }; const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, "foo"); }); Promise.all([promise1, promise2, promise3]).then((res) => console.log(res)); Porque está intentando invocar a then() en p2, que es un número.
Así es como implemento Promise.all()
EDITAR: antigua solución iterativa
Promise.all = async function (array) { const results = []; for (let index = 0; index < array.length; index++) { try { const value = await Promise.resolve(array[index]); results.push(value); } catch (error) { return Promise.reject(error); } } return Promise.resolve(results); }; const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, "foo"); }); Promise.all([promise1, promise2, promise3]).then((res) => console.log(res)); // print [3, 42, 'foo']