Implementar el método promesa.all
1- Uso de Promise.all
Para implementar funciones a la inversa, el requisito previo más crítico es comprender con precisión la API, la entrada, la salida y las precauciones.
Aquí hay una referencia directa a MDN:
El método Promise.all(iterable)? devuelve una instancia de Promise, en la que todas las promesas en el parámetro iterable están "resueltas" o parámetros. La devolución de llamada se completa (resolver) cuando no contiene una promesa, si hay una promesa en el parámetro que falla (rechazada), la devolución de llamada de esta instancia falla (rechazada) y el motivo de la falla es el resultado de la misma. primera promesa fallida.
MDN también brinda instrucciones detalladas más adelante:
Este método es útil cuando se agregan los resultados de retorno de múltiples promesas.
Cumplimiento:
Si el objeto iterable entrante está vacío, Promise.all devolverá sincrónicamente una promesa en el estado resuelto.
Si todas las promesas entrantes se completan, o no hay ninguna promesa en el objeto iterable entrante, la promesa devuelta por Promise.all se completa de forma asincrónica.
En cualquier caso, el resultado del estado de finalización de la promesa devuelto por Promise.all es una matriz que contiene los valores de todos los objetos de parámetros de iteración entrantes (incluidos los valores que no son de promesa).
Fallo/Rechazo:
Si una de las promesas entrantes falla (rechazada), Promise.all proporciona asincrónicamente el resultado fallido a la función de devolución de llamada de estado de falla, independientemente de si se cumplen otras promesas. terminado.
Personalmente, creo que MDN lo explica más claramente. Si aún estás confundido, puedes leer la explicación anterior con atención. O combínelo con el siguiente código para comprenderlo.
2 - Implementar manualmente Promise.all
Cuando estaba entrevistando a Meituan, el entrevistador vio que no podía escribirlo, así que dijo: "Ahora que sabes qué entrada y los resultados son, deberías poder Está escrito…”.
De hecho, el entrevistador no me menospreciaba y decía "No puedo hacerlo", sino que intentaba guiar mi pensamiento. Era solo que mis ideas de programación eran demasiado pobres en ese momento. , y al final todavía no lo escribí.
Pero el consejo del entrevistador es, de hecho, una buena forma de pensar. Independientemente de cómo se vea el código completo de Promise.all, incluida la optimización, etc.
Primero piense en el método "Promise.all (iterable)? Devuelve una instancia de Promise". function myPromiseAll(arr) { ?// El parámetro es un objeto iterable, generalmente una matriz // Devuelve una instancia de Promise
return new Promise((resolve, rechazar) => {
resolve("El entrevistador me pidió que escribiera una Promise.all");
// o
// rechazar("Soy demasiado estúpido para escribirla"); p>
});
}
let pResult = myPromiseAll() ?// El elemento no es una instancia de Promise
pResult.then(value=>{
console.log(pResult); // Salida: ?Promise {
console.log(valor); // Salida: Array(3) [ 1, 2, 3 ]
})
El La parte más difícil está aquí. ¿Todos los elementos son instancias de Promise?
Que no cunda el pánico, escriba primero el diseño de nivel superior y luego piense en los detalles (programación de arriba hacia abajo) function myPromiseAll(arr) {
let result = [] ;
devolver nueva Promesa((resolver, rechazar) => {
for(let i = 0; i < arr.length; i++) {
if(/*si es una instancia de Promise*/) {
} else {
result.push(arr [i]);
}
}
// Piénsalo primero, pon resolve aquí, ¿verdad
resolve(? resultado);
?
});
}
Continuar mejorando la función myPromiseAll( arr) {
let resultado = [];
return new Promise((resolver, rechazar) => {
// La matriz está vacía, resolver directamente
if( arr.length == 0) {
resolver(resultado);
}
for(let i = 0; i < arr.length; i++) {
if(arr[i].then) { // Si el elemento es una instancia de Promise, habrá un entonces función, que simplemente se usa como criterio de juicio
// El elemento es Promesa
arr[i].then(value => {<
/p>
console.log(value);
result.push(value);
// ¿Piensas en cuándo resolverlo? --- Todas las instancias de Promise están completas
if(result.length == arr.length) {
console.log("Todas están completas")
resolver(resultado);
}
})
} más {
resultado. push(arr[i]);
// Este código se repite como arriba. Piénselo, ¿se puede extraer y colocar afuera?
if(result.length == arr.length) {
resolver(resultado);
}
}
}
});
}
let p1 = nueva Promesa((resolver, rechazar)=> {
setTimeout(resolve, 2000, "P1 resuelto");
})
let p2 = new Promise((resolver, rechazar)=> {
setTimeout(resolve, 3000, "P2 resuelto");
})
let p3 = new Promise((resolver, rechazar)=> {
setTimeout (resolver, 4000, "P3 resuelto");
})
let pResult = myPromiseAll([p1,p2,p3]);
pResult. entonces(valor=>{
console.log(pResult);
console.log(valor);
})
// Salida
// P1 resuelto
// P2 resuelto
// P3 resuelto
// Todo completado
>// Promesa {
// Array(3) [ "P1 resuelto", "P2 resuelto" , "P3 resuelto" ]
Después de escribir el estado de finalización, todavía hay casos de falla:
Si una de las promesas entrantes falla (rechazada), Promise.all entrega asincrónicamente la falla resultado a la función de devolución de llamada en el estado fallido, independientemente de si se completaron otras promesas.
function myPromiseAll(arr) {
let result = [];
return new Promise((resolver, rechazar) => {
// Si la matriz está vacío, devuelve una matriz vacía directamente
if(arr.length == 0) {
resolve(result);
}
for(let i = 0; i < arr.length; i++) {
if(arr[i].then) { // Si el elemento es una Promesa Por ejemplo, habrá una función entonces, que simplemente se usa como criterio de juicio
// El elemento es Promesa
arr[i]. then(value => {
p>console.log(value);
result.push(value);
// Piensa en cuándo resolver
if(result.length == arr.length) {
console.log("Todo fue exitoso")
resolve(resultado);
}
}, err => {
console.log("Desafortunadamente, uno de ellos falló");
// ¿Notaste que no hay ninguno aquí como el juicio anterior result.length == arr.length, por qué
// Siempre que se encuentre resolución o rechazo, se acabó
rechazar(err);
})
} más {
resultado.push(arr[i]);
// Este párrafo El código se repite como arriba. Piénselo, ¿se puede extraer y colocar afuera?
if(result.length == arr.length) {
resolver(resultado);
}
}
}
});
}
let p1 = nueva Promesa((resolver, rechazar)=> {
setTimeout(rechazar, 2000, "P1 rechazado");
})
let p2 = new Promise((resolver, rechazar)=> {
setTimeout(resolver, 3000, "P2 resuelto");
})
l
et p3 = new Promise((resolver, rechazar)=> {
setTimeout(resolve, 4000, "P3 resuelto");
})
let pResult = myPromiseAll([p1,p2,p3]);
pResult.then(value=>{
console.log(pResult); ?// La salida es exitosa< / p>
console.log(value);
}, err => {
console.log(pResult); // ¿O falla la salida? /p >
console.log(err);
})
// Salida
// Desafortunadamente, uno de ellos falló
// Promesa {
// P1 rechazado
// P2 resuelto
// P3 resuelto< / p>
¿Por qué los resultados de P2 y P3 aparecen al final? Esto se debe a que, aunque se rechaza P1, P2 y P3 aún se ejecutan. Tenga en cuenta que MDN dice "independientemente de si se completan otras Promesas", no "se detienen otras Promesas". let p2 = new Promise((resolver, rechazar)=> {
setTimeout(resolve, 3000, "P2 resuelto");
})
let p3 = nueva Promesa((resolver, rechazar)=> {
setTimeout(resolve, 4000, "P3 resuelto");
})
let pResult = myPromiseAll([p2,55,p3]);
pResult.then(value=>{
console.log(pResult);
console. log(valor); // Salida [55, 'P2 resuelto', 'P3 resuelto']
}, err => {
console.log(pResult); p>
consola.log(err);