Mongoose: Capacidade de especificar quais ES6 promete usos do mangusto da biblioteca

Criado em 17 fev. 2015  ·  45Comentários  ·  Fonte: Automattic/mongoose

Veja a discussão em #1699

Comentários muito úteis

Sim require('mongoose').Promise = global.Promise fará com que o mangusto use promessas nativas. Você deve ser capaz de usar qualquer construtor de promessa ES6, mas agora só testamos com native, bluebird e Q

Todos 45 comentários

Estou realmente ansioso para poder usar o Promise.all(), para fazer algo depois que todo o trabalho do banco de dados tiver sido feito.

:+1:

Uma coisa que não ficou muito clara em https://github.com/LearnBoost/mongoose/issues/1699 é qual implementação será o padrão.

Bem, dado que não é uma versão para trás, mpromise terá que ser o padrão, mas você poderá substituir.

+1

:+1:

Existe uma filial onde isso está sendo hackeado? Eu não suporto o fluxo de tratamento de erros com mpromise e estou prestes a abrir a fonte para ver o que isso levaria.

promessa:

  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);

Tem que lidar com a rejeição e também colocar end lá. Sem end , exceções (por exemplo, eu tinha a classe NotFound digitada incorretamente) são engolidas silenciosamente e expressam apenas stalls.

pássaro azul:

  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);

Fazer promisifyAll(require('mongoose')) parece ainda estar funcionando com o Mongoose 4 até agora. Os testes de regressão que cobrem isso seriam muito direcionados?

Não no momento. A maior parte do trabalho acontecerá no módulo kareem conforme #2754 e vkarpov15/kareem#2, porque isso nos permitirá matar dois coelhos com uma cajadada e remover o absurdo de corte de ponta realmente bagunçado que foi escrito para fazer ganchos e promessas trabalhar juntos. Sinta-se à vontade para tentar, porém, estou aberto a PRs.

Mas por que devemos manter o suporte para outras bibliotecas de promessas? A especificação ES6 Promises agora é sólida e veio para ficar. Não podemos usar Promises ES6 puras, com um polyfill carregado quando não estão disponíveis em versões mais antigas do node?

Se sim, posso tentar.

O ponto é que você poderá usar qualquer biblioteca de promessas compatível com ES6 que desejar. Muitas pessoas ainda investem pesadamente no bluebird, quando, q, rsvp, etc. etc. e cada uma dessas bibliotecas tem suas peculiaridades particulares que um polyfill genérico não captura.

Estou aberto a sugestões alternativas - eu particularmente não gosto ou uso promessas, esse recurso é motivado pelo fato de que há uma montanha de problemas envolvendo pessoas pedindo "suporte ao recurso bluebird X em promessa" ou "suporte nativo a rsvp.js " e deixar que as pessoas tragam sua própria biblioteca de promessas para a festa é a maneira mais fácil de encerrar essas questões.

Eu vejo o que você quer dizer. Eu sou um grande usuário e apoiador das Promessas. Eu acho que deve ser considerado para fazer cumprir o padrão.
As promessas A+ foram escolhidas como a referência para o ES6. Eu sugeri o polyfill para garantir suporte para as versões de nós incompatíveis com ES6 (por exemplo, https://github.com/jakearchibald/es6-promise).

Deve estar nas mãos da outra biblioteca de promessas ser compatível e misturável com as promessas do ES6.

EDITAR:
E não haveria quebra na API atual ou está faltando alguma coisa?

A especificação Promises/A+ é muito diferente da especificação de promessas do ES6, que por sua vez é diferente das bibliotecas de promessas que listei nos comentários anteriores. Embora seja bom para mim se a miríade de bibliotecas de promessas todas consolidadas no ES6, duvido que isso aconteça, porque a beleza do código aberto é que algumas pessoas que amam promessas vão querer recursos adicionais e escrever suas próprias promessas bibliotecas.

Nenhuma alteração importante para a API atual, o que estou pensando é uma maneira de dizer mongoose.set('Promise', require('bluebird')); ou algo assim, então seria um opt-in e mpromise seria o padrão.

Ah certo, desculpe por esse erro.
Eu dei uma olhada na implementação atual e na outra biblioteca de promessas.

Acho que posso fazer algo assim funcionar:

mongoose.set('Promise', Promise);

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

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

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

// and so on...

Então, basicamente, você deve expor ao Mongoose sua promessa de objeto de escolha que tem os métodos resolve e reject .

Seria isso que você tinha em mente? Se sim, vou trabalhar em um pull request.

EDITAR:
Parece extremamente bobo escrever mongoose.set('Promise', Promise); . Eu acho que o ES6 deve ser o padrão, com a possibilidade de usar sua biblioteca de escolha (e prometer sempre que ES6 Promises não estiver disponível).

Claro, eu apreciaria sua ajuda. A parte complicada seria 1) fazê-lo funcionar com ganchos - veja vkarpov15/kareem#2, e 2) torná-lo compatível com mpromise.

Além disso, re: Q, usaremos require('q').Promise pois essa é a sintaxe Q mais próxima da especificação ES6

Obrigado pela sua contribuição, vai trabalhar nisso. Você prefere um pull request concorrido ou um PR em andamento?

Concluído é melhor, mas invariavelmente terei algumas sugestões. Deixe-me saber se você ficar preso

+1 para este recurso. eu gostaria de usar com bluebird

Desculpe por ser drástico - mas uma abordagem alternativa seria descontinuar completamente o suporte às promessas. Isso calaria qualquer um que usasse promessas pedindo o apoio de outras bibliotecas.
As pessoas que usam bibliotecas de promessas poderosas como o bluebird podem continuar usando de qualquer maneira, já que você expõe uma API de retorno de chamada e o bluebird pode encapsular isso a um custo 0 - na verdade, as chances são de que, como você não conhece ou usa promessas (como você disse), as chances são será mais lento e mais propenso a erros suportá-los manualmente de qualquer maneira.

@benjamingr 100% discordo. Agora com iojs e NodeJs se fundindo no Node 3.0, haverá suporte para ES6 Promises and Generators.

Abandonar o suporte seria um grande retrocesso.

Ou seja, Promise.promisifyAll(require("mongoose")) cria um wrapper rápido (mais rápido do que qualquer tentativa manual provável) para o Mongoose que é uma reclamação de padrões e envolve toda a API sem que você precise fazer nada a respeito. Na verdade, você mesmo pode fazer Promise.promisifyAll no objeto de exportação e expor as promessas do bluebird e o método de promessas duplas (save - saveAsync) de graça e depois dizer que você expõe uma interface de promessa do bluebird sem ter que fazer nenhum trabalho real.

Então, embora eu mesmo use promessas do bluebird - acho que tudo isso pode ser corrigido por uma seção nos documentos, em vez de complicar seu código codificando para duas interfaces.

@albertorestifo, exceto que nada será realmente descartado. Estou muito bem ciente do que são promessas (mais de 1500 pontos e 500 respostas no estouro de pilha :P) e até sou responsável por algumas partes de como elas funcionam no io.js (como https://github.com/ nodejs/io.js/issues/256).

Isso não muda o fato de que acredito que, como @vkarpov15 não usa promessas, ele não deveria ter que suportá-las em sua biblioteca _especialmente porque isso não traz nenhum benefício sobre o uso de promessas de qualquer maneira_. Você pode usar promessas com o mangusto com a mesma facilidade, mesmo que não as forneça - o suporte de implementação do mangusto internamente é mais para manter, provavelmente mais lento e mais propenso a erros. @vkarpov15 pode continuar trabalhando na API de retorno de chamada e prometer que os usuários podem envolver o Mongoose com promessas com um forro fácil de qualquer maneira.

@benjamingr que está supondo que alguém use uma biblioteca Promise externa. Estou me apegando ao que está nas especificações, e você sabe muito bem que não tem embalagem.

Eu entendo o que você quer dizer! Apoiar ambos cria uma enorme bagunça. Eu pessoalmente desprezo retornos de chamada, então eu os descartaria. Talvez devesse haver dois repositórios separados, um usando geradores e promessas, o outro usando retornos de chamada. Ambos manteriam a mesma estrutura e a API o mais próxima possível.

@benjamingr que está supondo que alguém use uma biblioteca Promise externa. Estou me apegando ao que está nas especificações, e você sabe muito bem que não tem embalagem.

Se você optar por usar uma implementação lenta, mais difícil de depurar e menos rica em recursos, é claro que é sua escolha: P, mas como isso está relacionado ao wrapper? É perfeitamente fácil escrever um wrapper similar ao promisifyAll do bluebird usando promessas nativas*.

Se você quiser uma versão do Mongoose habilitada para promessa como um pacote separado, veja como você pode fazer isso:

  • Etapa 1, abra seu editor favorito ou apenas um editor com o qual você esteja bem.
  • Etapa 2, digite module.exports = require("bluebird").promisifyAll(require("mongoose"))
  • Etapa 3, crie o arquivo package.json apropriado, publique no npm
  • Passo 4, dezenas de milhares de downloads.

Agora, eu sei o que você está pensando "isso não está usando promessas nativas", bem, você ainda pode excluir todos os métodos, exceto then e catch do protótipo de promessa e all e race de Promise e acabar com a mesma API - ou você pode apenas dizer às pessoas que está exportando promessas nativas - elas não saberão, pois são apenas duas implementações de Promises/A+, Eu prometo ;)

(* escrever rápido é mais difícil no nível do usuário porque não há uma maneira rápida de criar promessas agora, e é por isso que o io.js provavelmente exportará uma função promisify eventualmente - dito isso, ao usar um construtor de promessas, você está forçando-o a seja lento de qualquer maneira).

Essa é definitivamente uma alternativa decente. Eu gostaria de manter as promessas internas, no entanto, porque, goste ou não, é assim que os usuários usarão o mangusto, então podemos ter uma cobertura de teste sólida para isso, para que possamos apontar e dizer "é assim que você usa a biblioteca de promessas X com mangusto". A desvantagem quando você desconecta as coisas em módulos separados é que é complicado dizer "ok esta versão do mangusto-promises só funciona com o mangusto 3.8, este funciona com o mangusto >= 4.1" e é difícil para o mangusto evitar quebrar um wrapper de promessas abrangente .

Essa é definitivamente uma alternativa decente. Eu gostaria de manter as promessas internas, porque, gostando ou não, é assim que os usuários usarão o mangusto, então podemos ter uma cobertura de teste sólida para isso,

Por que você quer/precisa de cobertura de teste para isso? Não faz sentido testar promessas em seu código - as bibliotecas já têm testes - isso é como testar o módulo http quando você o está usando.

e é difícil para o mangusto evitar quebrar um invólucro de promessas abrangente.

O Bluebird faz algo realmente simples - ele encontra protótipos e adiciona métodos com o sufixo Async a eles - isso é muito simples e funciona bem na prática - é um forro com a maioria das bibliotecas, incluindo Mongoose e não quebrou mesmo uma vez para mim no ano passado.

Não sei por que você deseja manter muito código de costura que é potencialmente propenso a erros, ter que suportar manualmente duas APIs com seus casos extremos parece muito trabalho e você pode quebrar as coisas à medida que avança - você pode "pegue emprestado" o código promisifyAll do bluebird e adapte-o para trabalhar com outras bibliotecas de promessas (afinal, é de código aberto), mas eu certamente não faria isso manualmente.

"ok, esta versão do mangoose-promises só funciona com o mongoose 3.8, esta funciona com o mangoose >= 4.1" e é difícil para o mangoose evitar quebrar um wrapper de promessas abrangente.

Bem, você se importaria de me dar um exemplo de uma mudança de última hora que teria que acontecer se a promessa for automática?

1) Eu gostaria de testar as coisas do jeito que os usuários as usam.

2) Eu adoraria ser preguiçoso e evitá-lo, mas pelo que entendi, a maioria das outras bibliotecas de promessas não têm um equivalente promisifyAll. Suponho que é por isso que "suporte ao recurso Xpromise Y" é a solicitação de recurso do mangusto mais popular. Além disso, não temos nenhuma intenção de reescrever a promessa do Bluebird, apenas fazer as funções do mangusto retornar uma promessa nativamente.

3) Depende da implementação da promisificação e como você está usando :)

1) Eu gostaria de testar as coisas do jeito que os usuários as usam.

O que você quer dizer com testar a maneira como os usuários os usam? Você pode me mostrar uma analogia para retornos de chamada?

2) Eu adoraria ser preguiçoso e evitá-lo, mas pelo que entendi, a maioria das outras bibliotecas de promessas não têm um equivalente promisifyAll. Suponho que é por isso que "suporte ao recurso Xpromise Y" é a solicitação de recurso do mangusto mais popular. Além disso, não temos nenhuma intenção de reescrever a promessa do Bluebird, apenas fazer as funções do mangusto retornar uma promessa nativamente.

Você não precisa reescrever, você pode aceitar - não é genérico, pois uma implementação genérica seria mais lenta.

Também não é preguiça não implementar manualmente um recurso amplamente disponível. O NodeJS é preguiçoso por não colocar o express no core? O TC39 é preguiçoso por não colocar sublinhado no núcleo? Aderindo a uma convenção (retornos de chamada), você está dando aos usuários a capacidade de usar qualquer primitiva de simultaneidade que desejarem.

3) Depende da implementação da promisificação e como você está usando :)

Bem, a promessa do bluebird, ou Q's ou When's - eles variam na implementação, mas todos fazem a mesma coisa - então escolha um que você goste. Eu só estou querendo saber como ele iria quebrar.

Há uma coisa que está faltando nesta discussão aqui:

Se o mangusto retornar uma promessa padrão (por padrão, significando a implementação nativa do ES6), não deveria ser compatível com qualquer biblioteca Promise compatível com ES6? Eu posso fazer Promise.all([model.query().exec(), ...]) muito bem, assim como o pássaro azul, q, quando equivalente.

Então, por que não retornar callbacks e promessas padrão (como está fazendo agora, mas "se livrar" de mpromise) e deixar o usuário usar sua biblioteca de promessas favorita? Ou estou perdendo alguma coisa aqui?

@albertorestifo bem, as promessas nativas são lentas no momento e levará tempo, potencialmente anos antes de atingirem a paridade com as bibliotecas do usuário - principalmente isso.

@benjamingr você faz alguns bons pontos. O ponto principal das promessas do mongoose é permitir que você use yield com operações assíncronas do mongoose sem qualquer outra biblioteca, e é por isso que estamos mantendo as promessas no futuro próximo. IMO isso é algo que realmente deveria fazer parte do núcleo do mangusto daqui para frente.

Q ou quando tem capacidade de prometer?

Q ou quando tem capacidade de prometer?

Sim, praticamente todas as bibliotecas de promessas que conheço oferecem algum tipo de promessa:

Aqui é quando: https://github.com/cujojs/when/blob/master/docs/api.md#nodeliftall
Aqui está Q: https://github.com/krisowal/q/wiki/API-Reference#qnfbindnodefunc -args

As promessas nativas ainda não o têm, mas é algo que está sendo trabalhado - uma vez que existe um caminho rápido para criar promessas (ou seja - não o construtor de promessas), o NodeJS provavelmente o suportará no núcleo para promessas nativas (já que pode' t ser feito _fast_ em userland).

O ponto principal das promessas do mongoose é permitir que você use yield com operações assíncronas do mongoose sem qualquer outra biblioteca

Você precisa de uma biblioteca para usar yield de uma maneira significativa com promessas de qualquer maneira. Se você pode escrever os 9 LoC que bombeiam um gerador como uma função assíncrona, você pode definitivamente escrever promisify - e se você for como a maioria dos usuários, usará uma biblioteca para isso de qualquer maneira.

Definitivamente, vejo o desejo/necessidade de permitir promessas no Mongoose, elas são o caminho a seguir e como a linguagem faz concorrência agora, mas honestamente acho que fazê-lo manualmente, método por método, será doloroso. Pode ser benéfico apenas demonstrar como isso é feito usando bibliotecas em uma seção "usando com promessas" ou "usando com geradores" na documentação.

O problema é que já fizemos isso método por método, só precisamos modificar o wrapper de promessa interno. De qualquer forma, não podemos remover as promessas do núcleo até o 5.0. Eu sou receptivo à ideia de desaprovar, @benjamingr faz alguns bons argumentos que vou ter que considerar de perto, mas acho que o próximo passo seria #2688 de qualquer maneira.

Você obviamente tem mais experiência com o Mongoose e, mais importante, com os usuários - então eu entendo essa escolha. Muito obrigado por me ouvir.

Digitei "its", mas meu iPhone sentiu que deveria corrigi-lo automaticamente para "it's" e o GitHub sentiu que editar comentários não é um caso de uso interessante. Desculpem o spam de comentários duplos :)

Você pode editar comentários no site clicando no lápis no canto superior direito do seu comentário.

Estou sempre aberto a um bom debate, especialmente um que me ensine algo novo :beers: Posso enviar um ping mais tarde para discutir mais :)

O futuro pertence às promessas nativas, ao que parece. O Mongoose é um padrão da indústria para operações mongo, é totalmente válido que ele também dependa de promessas padrão.

As promessas padrão inevitavelmente amadurecerão e se tornarão mais difundidas do que qualquer estrutura. Um humilde +1 por usá-los.

@iliakan talvez no futuro. Eu não esperaria que as promessas nativas se tornassem o "padrão" até meados de 2016, no mínimo, as várias bibliotecas de promessas fragmentadas estão profundamente enraizadas e têm muitas peculiaridades sutis. De qualquer forma, o mangusto não pode mudar para 'nativo por padrão' sem uma enorme mudança para trás.

@vkarpov15 claro que entendi.

O que poderia ser benéfico enquanto isso - uma página simples que descreve as principais incompatibilidades entre promessas e promessas nativas. Pelo menos coisas que você não deveria tentar com mpromise ;)

Eu entendi que não há catch agora, e essas são todas as limitações?

Não faço ideia, ainda não me aprofundei na API do ES6. mpromise implementa Promises/A+ e nada mais, o que significa que não há .catch(), nenhum rastreamento de pilha longo, etc. etc. Basicamente, qualquer coisa que não seja .then() está fora do escopo da implementação do mpromise.

De um modo geral, algo que implementa Promises/A+ também implementa promessas ES6 de uma perspectiva de alto nível, mas o inverso não é verdadeiro. Promises/A+ é muito específico sobre os detalhes de implementação de baixo nível, por exemplo, bluebird não obedece Promises/A+ exatamente, e não tenho certeza sobre outras bibliotecas de promessas comuns, mas tenho certeza de que elas não obedecem à especificação em suas próprias maneiras únicas. Isso é o que vai tornar isso particularmente complicado.

Você quer dizer, agora pode usar bluebird e promessas nativas?

Sim require('mongoose').Promise = global.Promise fará com que o mangusto use promessas nativas. Você deve ser capaz de usar qualquer construtor de promessa ES6, mas agora só testamos com native, bluebird e Q

@vkarpov15 Isso é ótimo! Muito obrigado!

@vkarpov15 Muito obrigado! Bom trabalho!

Sim, definitivamente. Isso é muito legal! :)

@vkarpov15 Isso é muito bom

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

CodeurSauvage picture CodeurSauvage  ·  3Comentários

weisjohn picture weisjohn  ·  3Comentários

ghost picture ghost  ·  3Comentários

adamreisnz picture adamreisnz  ·  3Comentários

Igorpollo picture Igorpollo  ·  3Comentários