Mongoose: Capacidad para especificar qué usos de la mangosta de la biblioteca ES6 promete

Creado en 17 feb. 2015  ·  45Comentarios  ·  Fuente: Automattic/mongoose

Ver discusión en #1699

Comentario más útil

require('mongoose').Promise = global.Promise hará que mongoose use promesas nativas. Sin embargo, debería poder usar cualquier constructor de promesa ES6, pero en este momento solo probamos con native, bluebird y Q

Todos 45 comentarios

Tengo muchas ganas de poder usar Promise.all(), para hacer algo después de que se haya realizado todo el trabajo de la base de datos.

:+1:

Una cosa que no estaba muy clara en https://github.com/LearnBoost/mongoose/issues/1699 es qué implementación será la predeterminada.

Bueno, dado que no es una versión retrospectiva, mpromise tendrá que ser el valor predeterminado, pero podrá anularlo.

+1

:+1:

¿Hay una rama donde esto está siendo pirateado? No soporto el flujo de manejo de errores con mpromise y estoy a punto de abrir la fuente para ver qué se necesita.

promesa:

  query.exec()
    .then(function(ou) {
      if(!ou) {
        return next(new errors.http.NotFound('The specified OU was either not found, or your credentials lack the required permissions to view it.'));
      }

      res.send(ou);
    }, next)
    .end(next);

Tiene que manejar el rechazo y también poner end allí. Sin end , las excepciones (por ejemplo, tenía la clase NotFound mal escrita) se tragan silenciosamente y expresan simplemente paradas.

azulejo:

  query.exec()
    .then(function(ou) {
      if(!ou) {
        return next(new errors.http.NotFound('The specified OU was either not found, or your credentials lack the required permissions to view it.'));
      }

      res.send(ou);
    })
    .catch(next);

Hacer promisifyAll(require('mongoose')) parece estar funcionando con Mongoose 4 hasta ahora. ¿Las pruebas de regresión que cubren esto serían demasiado específicas?

No en este momento. La mayor parte del trabajo se llevará a cabo en el módulo kareem según #2754 y vkarpov15/kareem#2, porque eso nos permitirá matar dos pájaros de un tiro y eliminar las tonterías realmente desordenadas que se escribieron para hacer ganchos y promesas. trabajar juntos. Sin embargo, siéntase libre de intentarlo, estoy abierto a las relaciones públicas.

Pero, ¿por qué deberíamos mantener el soporte para la biblioteca de otras promesas? La especificación ES6 Promises ahora es sólida como una roca y está aquí para quedarse. ¿No podemos simplemente usar ES6 Promises puros, con un polyfill cargado cuando no están disponibles en versiones anteriores de node?

Si es así, puedo intentarlo.

El punto es que podrá usar cualquier biblioteca de promesas compatible con ES6 que desee. Mucha gente todavía está muy interesada en bluebird, when, q, rsvp, etc. etc. y cada una de esas bibliotecas tiene sus propias peculiaridades particulares que un polyfill genérico no capturará.

Estoy abierto a sugerencias alternativas: no me gustan ni uso promesas en particular, esta función está motivada por el hecho de que hay una montaña de problemas que involucran a personas que solicitan "soporte para la característica X de bluebird en mpromise" o "soporte nativo de rsvp.js y dejar que las personas traigan su propia biblioteca de promesas a la fiesta es la forma más fácil de cerrar estos problemas.

Veo a que te refieres. Soy un gran usuario y partidario de Promises. Creo que debería considerarse hacer cumplir la norma.
Las promesas A+ han sido elegidas como opción para el ES6. Sugerí el polyfill para garantizar la compatibilidad con las versiones de nodos incompatibles con ES6 (por ejemplo, https://github.com/jakearchibald/es6-promise).

Debería estar en manos de la biblioteca de otras promesas para que sea compatible y mezclable con las promesas de ES6.

EDITAR:
¿Y no habría interrupciones en la API actual o me estoy perdiendo algo?

La especificación Promises/A+ es muy diferente de la especificación de promesas de ES6, que a su vez es diferente de las bibliotecas de promesas que enumeré en los comentarios anteriores. Si bien sería bueno para mí si la miríada de bibliotecas de promesas se consolidara en ES6, dudo que eso suceda alguna vez, porque la belleza del código abierto es que algunas personas que aman las promesas querrán características adicionales y escribirán sus propias promesas. bibliotecas

No hay cambios importantes para la API actual, lo que estoy pensando es una forma de decir mongoose.set('Promise', require('bluebird')); o algo así, por lo que sería una opción y mpromise sería el valor predeterminado.

Oh cierto, perdón por ese error.
He echado un vistazo a la implementación actual y la otra biblioteca de promesas.

Creo que puedo hacer que algo como esto funcione:

mongoose.set('Promise', Promise);

mongoose.set('Promise', require('bluebird'));

mongoose.set('Promise', require('q').defer());

mongoose.set('Promise', require('when').defer());

// and so on...

Básicamente, debe exponer a Mongoose su objeto de promesa de elección que tiene los métodos resolve y reject .

¿Sería esto lo que tenías en mente? Si es así, trabajaré en una solicitud de extracción.

EDITAR:
Se siente extremadamente tonto escribir mongoose.set('Promise', Promise); . Creo que ES6 debería ser el predeterminado, con la posibilidad de usar la biblioteca de su elección (y prometer siempre que ES6 Promises no esté disponible).

Claro, agradecería su ayuda. La parte complicada sería 1) hacer que funcione con ganchos - ver vkarpov15/kareem#2, y 2) hacerlo compatible con versiones anteriores de mpromise.

Además, re: Q, usaremos require('q').Promise ya que esa es la sintaxis Q más cercana a la especificación ES6

Gracias por tu aporte, trabajaré en ello. ¿Prefieres una solicitud de extracción completa o una PR en curso?

Completado es mejor, pero invariablemente tendré algunas sugerencias. Avísame si te quedas atascado

+1 para esta función. me gustaría usar con bluebird

Perdón por ser drástico, pero un enfoque alternativo sería desaprobar el soporte de promesas por completo. Eso haría callar a cualquiera que use promesas pidiendo el apoyo de otras bibliotecas.
Las personas que usan poderosas bibliotecas de promesas como bluebird pueden seguir usándolas de todos modos, ya que expone una API de devolución de llamada y bluebird puede envolver eso trivialmente a un costo de 0; de hecho, es probable que, dado que no sabe o usa promesas (como usted dijo) las posibilidades son será más lento y más propenso a errores admitirlos manualmente de todos modos.

@benjamingr 100% en desacuerdo. Ahora, con la fusión de iojs y NodeJs en Node 3.0, habrá soporte para ES6 Promises and Generators.

Retirar el soporte sería un gran paso atrás.

Es decir, Promise.promisifyAll(require("mongoose")) crea un envoltorio rápido (más rápido que cualquier intento manual probable) para Mongoose que cumple con los estándares y rodea toda la API sin que usted tenga que hacer nada al respecto. De hecho, puede hacer Promise.promisifyAll en el objeto de exportaciones usted mismo y exponer las promesas de bluebird y el método de promesas duales (save - saveAsync) de forma gratuita y luego decir que expone una interfaz de promesa de bluebird sin tener que hacer ningún trabajo real.

Entonces, aunque yo mismo uso las promesas de bluebird, creo que todo esto se puede arreglar en una sección en los documentos en lugar de complicar su código codificando en dos interfaces.

@albertorestifo excepto que en realidad no se eliminará nada. Soy muy consciente de lo que son las promesas (más de 1500 puntos y 500 respuestas en stack overflow :P) e incluso soy responsable de algunas partes de cómo funcionan en io.js (como https://github.com/ nodejs/io.js/issues/256).

Eso no cambia el hecho de que creo que, dado que @vkarpov15 no usa promesas, no debería tener que respaldarlas en su biblioteca, especialmente porque eso no trae ningún beneficio sobre el uso de promesas de todos modos_. Puede usar promesas con mongoose con la misma facilidad, incluso si no las proporciona: la implementación interna de soporte de mongoose es más para mantener, probablemente más lenta y más propensa a errores. @vkarpov15 puede continuar trabajando en la API de devolución de llamada y los usuarios de promesas pueden envolver Mongoose con promesas con una sola línea de todos modos.

@benjamingr que supone que uno usa una biblioteca Promise externa. Me quedo con el de las especificaciones, y lo sabes muy bien, no tiene envoltorio.

Veo tu punto. Apoyar a ambos crea un gran lío. Personalmente, desprecio las devoluciones de llamadas, así que las dejaría en su lugar. Tal vez debería haber dos repositorios separados, uno que use generadores y promesas, el otro que use devoluciones de llamada. Ambos mantendrían la misma estructura y la API lo más cercana posible.

@benjamingr que supone que uno usa una biblioteca Promise externa. Me quedo con el de las especificaciones, y lo sabes muy bien, no tiene envoltorio.

Si elige usar una implementación lenta, más difícil de depurar y con menos funciones, esa es, por supuesto, su elección: P, pero ¿cómo se relaciona eso con el contenedor? Es perfectamente fácil escribir un envoltorio similar al promisifyAll de bluebird usando promesas nativas*.

Si desea una versión habilitada para promesas de Mongoose como un paquete separado, así es como podría hacerlo:

  • Paso 1, abra su editor favorito o simplemente un editor con el que esté de acuerdo.
  • Paso 2, escriba module.exports = require("bluebird").promisifyAll(require("mongoose"))
  • Paso 3, cree el archivo package.json apropiado, publíquelo en npm
  • Paso 4, decenas de miles de descargas.

Ahora, sé lo que está pensando "esto no está usando promesas nativas", bueno, aún puede eliminar todos los métodos excepto then y catch del prototipo de promesa y all y race de Promise y terminar con la misma API, o simplemente puede decirle a la gente que está exportando promesas nativas, no lo sabrán ya que son solo dos implementaciones de Promises/A+, Prometo ;)

(*escribirlo rápido es más difícil en el nivel de usuario porque no hay una forma rápida de crear promesas en este momento, por lo que es probable que io.js exporte una función de promesa eventualmente; dicho esto, al tomar un constructor de promesas lo estás obligando a hacerlo) ser lento de todos modos).

Esa es definitivamente una alternativa decente. Sin embargo, me gustaría mantener las promesas internamente, porque, nos guste o no, así es como los usuarios van a usar mongoose, por lo que también podríamos tener una cobertura de prueba sólida para ello, para que podamos señalar y decir "así es como usas la biblioteca de promesas X con mangosta". La desventaja cuando desconecta cosas en módulos separados es que es difícil decir "bien, esta versión de mongoose-promises solo funciona con mongoose 3.8, esta funciona con mongoose>= 4.1" y es difícil para mongoose evitar romper un contenedor de promesas generales .

Esa es definitivamente una alternativa decente. Sin embargo, me gustaría mantener las promesas internas porque, nos guste o no, así es como los usuarios van a usar mongoose, por lo que también podríamos tener una cobertura de prueba sólida para ello,

¿Por qué querría/necesitaría cobertura de prueba para ello? No tiene sentido probar las promesas en sí mismas en su código; las bibliotecas ya tienen pruebas; esto es como probar el módulo http cuando lo está usando.

y es difícil para la mangosta evitar romper un envoltorio de promesas generales.

Bluebird hace algo realmente simple: encuentra prototipos y luego agrega métodos con el sufijo Async . Esto es realmente simple y funciona bien en la práctica. Es una línea con la mayoría de las bibliotecas, incluida Mongoose, y no se rompió incluso una vez para mí en el último año.

No estoy seguro de por qué querría mantener una gran cantidad de código de unión que es potencialmente propenso a errores, tener que admitir manualmente dos API con sus casos extremos suena como mucho trabajo y puede romper las cosas sobre la marcha, puede "tome prestado" el código promisifyAll de bluebird y adáptelo para que funcione con otras bibliotecas prometedoras (después de todo, es de código abierto), pero ciertamente no lo haría manualmente.

"bien, esta versión de mongoose-promises solo funciona con mongoose 3.8, esta funciona con mongoose >= 4.1" y es difícil para mongoose evitar romper un envoltorio de promesas generales.

Bueno, ¿te importaría darme un ejemplo de un cambio radical que tendría que ocurrir si la promisificación es automática?

1) Me gustaría probar cosas de la forma en que los usuarios las usan.

2) Me encantaría ser perezoso y evitarlo, pero según tengo entendido, la mayoría de las otras bibliotecas de promesas no tienen un equivalente de promisifyAll. Supongo que esta es la razón por la que "apoyar la función Xpromise Y" es la solicitud de función de mangosta más popular. Además, no tenemos ninguna intención de reescribir la promesa de Bluebird, solo hacer que las funciones de mangosta devuelvan una promesa de forma nativa.

3) Depende de la implementación de la promisificación y de cómo la uses :)

1) Me gustaría probar cosas de la forma en que los usuarios las usan.

¿Qué quiere decir con probar la forma en que los usuarios los usan? ¿Me puede mostrar una analogía para las devoluciones de llamada?

2) Me encantaría ser perezoso y evitarlo, pero según tengo entendido, la mayoría de las otras bibliotecas de promesas no tienen un equivalente de promisifyAll. Supongo que esta es la razón por la que "apoyar la función Xpromise Y" es la solicitud de función de mangosta más popular. Además, no tenemos ninguna intención de reescribir la promesa de Bluebird, solo hacer que las funciones de mangosta devuelvan una promesa de forma nativa.

No tiene que volver a escribir, puede tomarlo; no es genérico, ya que una implementación genérica sería más lenta.

Tampoco es pereza no implementar manualmente una característica ampliamente disponible. ¿NodeJS es perezoso por no poner Express en el núcleo? ¿TC39 es perezoso por no poner guiones bajos en el núcleo? Al apegarse a una convención (devoluciones de llamada), le brinda a los usuarios la capacidad de usar cualquier primitiva de concurrencia que deseen.

3) Depende de la implementación de la promisificación y de cómo la uses :)

Bueno, la promisificación de bluebird, o Q's o When's: varían en la implementación, pero todas hacen lo mismo, así que solo elija una que le guste. Me pregunto cómo se rompería.

Hay una cosa que me estoy perdiendo en esta discusión aquí:

Si mongoose devuelve una promesa estándar (por estándar significa la implementación nativa de ES6), ¿no debería ser compatible con cualquier biblioteca Promise compatible con ES6? Puedo hacer Promise.all([model.query().exec(), ...]) muy bien, así como el pájaro azul, q, cuando sea equivalente.

Entonces, ¿por qué no devolver las devoluciones de llamada y las promesas estándar (como lo está haciendo ahora, pero "deshacerse" de mpromise) y dejar que el usuario use su biblioteca de promesas favorita? ¿O me estoy perdiendo algo aquí?

@albertorestifo bueno, las promesas nativas son lentas en este momento y tomará tiempo, posiblemente años antes de que alcancen la paridad con las bibliotecas de usuarios, principalmente eso.

@benjamingr haces algunos buenos puntos. El punto principal de las promesas de mongoose es permitirle usar yield con operaciones asincrónicas de mongoose sin ninguna otra biblioteca, razón por la cual mantenemos las promesas en el futuro previsible. En mi opinión, eso es algo que realmente debería ser parte del núcleo de mongoose en el futuro.

¿Q o Cuándo tienen capacidad de promisificación?

¿Q o Cuándo tienen capacidad de promisificación?

Sí, prácticamente todas las bibliotecas de promesas generalizadas que conozco ofrecen algún tipo de promesa:

Aquí es cuando: https://github.com/cujojs/when/blob/master/docs/api.md#nodeliftall
Aquí está la P: https://github.com/kriskowal/q/wiki/API-Reference#qnfbindnodefunc -args

Las promesas nativas aún no lo tienen, pero es algo en lo que se está trabajando: una vez que exista una ruta rápida para crear promesas (es decir, no el constructor de promesas), es probable que NodeJS lo admita en el núcleo para promesas nativas (ya que puede ' no se puede hacer _rápido_ en el espacio del usuario).

El punto principal de las promesas de mongoose es permitirle usar el rendimiento con operaciones asíncronas de mongoose sin ninguna otra biblioteca

Necesita una biblioteca para usar yield de manera significativa con promesas de todos modos. Si puede escribir los 9 LoC que bombean un generador como una función asíncrona usted mismo, definitivamente puede escribir promisify, y si es como la mayoría de los usuarios, usa una biblioteca para eso de todos modos.

Definitivamente veo el deseo/necesidad de permitir promesas en Mongoose, son el camino a seguir y cómo el lenguaje hace concurrencia ahora, pero honestamente creo que hacerlo manualmente método por método será doloroso. Podría ser beneficioso simplemente demostrar cómo se hace usando bibliotecas en una sección "usando con promesas" o "usando con generadores" en la documentación.

El caso es que ya lo hemos hecho método por método, solo nos falta modificar el envoltorio interno de la promesa. De cualquier manera, no podemos eliminar las promesas del núcleo hasta la versión 5.0. Estoy de acuerdo con la idea de desaprobarlo, @benjamingr presenta algunos buenos argumentos que tendré que considerar de cerca, pero creo que el siguiente paso sería el #2688 de todos modos.

Obviamente, tiene más experiencia con Mongoose y, lo que es más importante, sus usuarios, por lo que entiendo esa elección. Muchas gracias por escucharme.

Escribí "su", pero mi iPhone sintió que debería corregirlo automáticamente a "es" y GitHub sintió que editar comentarios no es un caso de uso interesante. Lo siento por el spam de doble comentario :)

Puede editar comentarios en el sitio web si hace clic en el lápiz en la parte superior derecha de su comentario.

Siempre estoy abierto a un buen debate, especialmente uno que me enseñe algo nuevo :cervezas: Puedo enviarte un ping más tarde para discutir más :)

El futuro pertenece a las promesas nativas, al parecer. Mongoose es un estándar de la industria para mongo ops, es totalmente válido que también se base en promesas estándar.

Las promesas estándar inevitablemente madurarán y se generalizarán más que cualquier marco. Un humilde +1 por usarlos.

@iliakan quizás en el futuro. No esperaría que las promesas nativas se convirtieran en el "estándar" hasta mediados de 2016 como muy pronto, las diversas bibliotecas de promesas fragmentadas están demasiado arraigadas y tienen demasiadas peculiaridades sutiles. De cualquier manera, mangosta no puede cambiar a 'nativo por defecto' sin un cambio masivo hacia atrás.

@ vkarpov15 Seguro que lo entiendo.

Mientras tanto, lo que podría ser beneficioso: una página simple que describa las principales incompatibilidades entre la promesa y las promesas nativas. Al menos cosas que no deberías probar con mpromise ;)

¿Entiendo bien que no hay catch este momento, y esas son todas las limitaciones?

No tengo idea, realmente no he profundizado en la API de ES6. mpromise implementa Promises/A+ y nada más, lo que significa que no hay .catch(), ni rastros largos de pila, etc., etc. Básicamente, cualquier cosa que no sea .then() está fuera del alcance de la implementación de mpromise.

En términos generales, algo que implementa Promesas/A+ también implementa promesas de ES6 desde una perspectiva de alto nivel, pero lo contrario no es cierto. Promises/A+ es muy específico sobre los detalles de implementación de bajo nivel, por ejemplo, bluebird no obedece exactamente a Promises/A+, y no estoy seguro acerca de otras bibliotecas de promesas comunes, pero estoy seguro de que no obedecen la especificación en sus propias formas únicas. Eso es lo que va a hacer que esto sea particularmente complicado.

¿Quieres decir, ahora puede usar bluebird y promesas nativas?

require('mongoose').Promise = global.Promise hará que mongoose use promesas nativas. Sin embargo, debería poder usar cualquier constructor de promesa ES6, pero en este momento solo probamos con native, bluebird y Q

@vkarpov15 ¡ Esto es genial! ¡Muchas gracias!

@vkarpov15 ¡Muchas gracias! ¡Gran trabajo!

Sí, definitivamente. ¡Eso es realmente genial! :)

@vkarpov15 Esto es muy bueno

¿Fue útil esta página
0 / 5 - 0 calificaciones