¿Cuál es la promesa explícita antipatrón de construcción y cómo la evito?

javascript promise q bluebird es6-promise


Estaba escribiendo un código que hace algo que parece:

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

Alguien me dijo que esto se llama " antipatrón diferido " o " antipatrón de constructor de promesas " respectivamente, ¿qué tiene de malo este código y por qué se llama antipatrón ?





Answer 1 Benjamin Gruenbaum


El antipatrón diferido (ahora antipatrón de construcción explícita) acuñado por Esailija es un antipatrón común que las personas que son nuevas en las promesas hacen, lo hice yo mismo cuando las usé por primera vez. El problema con el código anterior es que no puede utilizar el hecho de que promete la cadena.

Las promesas pueden encadenarse con .then y usted puede devolverlas directamente. Su código en getStuffDone puede reescribirse como:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

Las promesas se refieren a hacer más legible el código asíncrono y a comportarse como un código síncrono sin ocultar ese hecho.Las promesas representan una abstracción sobre un valor de una operación de tiempo,abstraen la noción de una declaración o expresión en un lenguaje de programación.

Solo debe usar objetos diferidos cuando convierte una API a promesas y no puede hacerlo automáticamente, o cuando escribe funciones de agregación que se expresan más fácilmente de esta manera.

Citando a Esailija:

Este es el antipatrón más común.Es fácil caer en esto cuando no entiendes realmente las promesas y piensas en ellas como emisores de eventos glorificados o utilidad de devolución de llamada.Recapitulemos:las promesas se refieren a hacer que el código asíncrono retenga la mayoría de las propiedades perdidas del código síncrono como la indentación plana y un canal de excepción.




Answer 2 Bergi


¿Qué tiene de malo?

¡Pero el patrón funciona!

Qué afortunado.Desafortunadamente,probablemente no lo hace,ya que probablemente olvidaste algún caso límite.En más de la mitad de los casos que he visto,el autor ha olvidado ocuparse del manejador de errores:

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

Si la otra promesa es rechazada,esto pasará desapercibido en lugar de ser propagado a la nueva promesa (donde se manejaría)-y la nueva promesa queda pendiente para siempre,lo que puede inducir fugas.

Lo mismo sucede en el caso de que su código de devolución de llamada provoque un error, por ejemplo, cuando el result ado no tiene una property y se produce una excepción. Eso quedaría sin control y dejaría la nueva promesa sin resolver.

Por el contrario, el uso de .then() ocupa automáticamente de estos dos escenarios y rechaza la nueva promesa cuando ocurre un error:

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

El antipatrón diferido no solo es engorroso, sino también propenso a errores . Usar .then() para encadenar es mucho más seguro.

¡Pero yo me he encargado de todo!

¿En serio? Bien.Sin embargo,esto será bastante detallado y copioso,especialmente si usas una biblioteca de promesas que soporte otras características como la cancelación o el paso de mensajes.O tal vez lo haga en el futuro,o quieres cambiar tu biblioteca por una mejor? No querrás reescribir tu código para eso.

Los métodos de las bibliotecas ( then ) no solo admiten de forma nativa todas las características, sino que también pueden tener ciertas optimizaciones en su lugar. Su uso probablemente acelerará su código, o al menos permitirá que sea optimizado por futuras revisiones de la biblioteca.

¿Cómo lo evito?

Por lo tanto, cada vez que se encuentre creando manualmente una Promise o una Promesa Deferred y ya estén involucradas, consulte primero la API de la biblioteca . El antipatrón diferido a menudo es aplicado por personas que ven las promesas [solo] como un patrón de observación, pero las promesas son más que devoluciones de llamada : se supone que son componibles. Cada biblioteca decente tiene muchas funciones fáciles de usar para la composición de promesas de todas las maneras imaginables, cuidando todas las cosas de bajo nivel con las que no desea lidiar.

Si ha encontrado la necesidad de componer algunas promesas de una nueva forma que no esté apoyada por una función de ayuda existente,escribir su propia función con Deferreds inevitables debería ser su última opción.Considere la posibilidad de cambiar a una biblioteca con más funciones,o bien presente un error en su biblioteca actual.Su mantenedor debería ser capaz de derivar la composición de las funciones existentes,implementar una nueva función de ayuda para usted y/o ayudar a identificar los casos límite que deben ser tratados.