Angular.js: Suporte a module.run () assíncrono

Criado em 13 set. 2013  ·  62Comentários  ·  Fonte: angular/angular.js

Queremos emitir algumas chamadas $ http no bloco de execução do módulo, idealmente, a execução deve terminar somente depois que $ http e o processamento terminar, antes que a compilação do dom aconteça.

Lots of comments won't fix feature

Comentários muito úteis

jfcfxekzl5m
Recurso simples, mas muito difícil de implementar. 😕

Todos 62 comentários

Isso não é tão fácil, mas deve ser investigado.

A maneira como o Jasmine faz isso é definindo um sinalizador, que permitirá que a função seja executada e espere pelo retorno de chamada até que o sinalizador seja definido como true ou até que um tempo limite seja disparado.

Basicamente, algo assim:

var flag = false;
$http(...).success(flag = true);
$timeout(function () {
    flag = true;
    // Or add some error handling stuff here
}, 5000);
while (!flag) {};

Não é bonito, mas deve servir. O código acima não foi testado, então você pode precisar modificá-lo um pouco. Está ficando tarde aqui. Esperançosamente, algo para te ajudar até que algo um pouco mais bonito apareça.

+1

Em um segundo, porém, isso leva à incapacidade de desenhar telas de carregamento extravagantes usando diretivas angulares ...

+1

$routeProvider com resolve resolve isso? Talvez eu não tenha entendido o problema ...

Isso é mais para suporte de inicialização de módulo assíncrono. Dito isso, não preciso mais disso em meus projetos atuais.

@shahata $routeprovider faz isso, mas nem todos os casos de uso de run s de promessa usam rotas. No meu caso de uso, é para um módulo que envolve uma diretiva e não tem nada a ver com rotas.

+1

verifique se a função de execução retorna uma promessa e só prossiga quando for resolvida. já que runBlocks é uma matriz de funções, não deve ser difícil

+1

+1 embaraçoso por ter sido ignorado

alguma ideia de quando isso vai pousar? tão frustrante ter que mover o material de inicialização para resolver no roteador, principalmente porque às vezes o código de inicialização é agnóstico de url (ou seja, deve ser inicializado para qualquer tipo de URL que o usuário chegue ao seu SPA)

eu não acho que o angular receberá qualquer aprimoramento daqui em diante. estão todos sendo adicionados ao angular 2.0

por quanto tempo o método run meia-boca permanecerá síncrono? é normal e compreensível que config não suporte chamadas assíncronas, uma vez que você não tem nenhum provedor que faça $http chamadas, mas run sim. veja o tipo de hacks que a falta desse recurso (que deveria estar presente desde o início) causa
https://github.com/philippd/angular-deferred-bootstrap/blob/master/src/deferred-bootstrap.js

é embaraçoso

+1

@btford está examinando como os casos de uso em torno disso podem ser suportados por meio do novo roteador, em vez de blocos de execução internos.

+1

+1

+1

+1

O principal problema que temos é que $q é criado dentro de um módulo que está sendo carregado quando os runBlocks estão sendo executados. Isso significa que precisaríamos de alguma forma extrair "alguns" dos serviços (ou talvez módulos) e criá-los primeiro e, em seguida, ter uma segunda passagem que carregue o resto dos módulos (e serviços, blocos de execução, etc) após $ q ter foi criado.

@lgalfaso - talvez você pudesse examinar isso um pouco mais como parte do seu $injector trabalho no final desta semana (ou na próxima)?

Eu sei que é apenas uma solução alternativa, mas normalmente resolvi o problema de ter alguma lógica de inicialização assíncrona usando o roteador ui angular e tendo um estado abstrato raiz em combinação com resolver. O estado abstrato raiz deve ser sempre resolvido primeiro, por isso é um bom lugar para carregar configurações, exibir animações de carregamento, etc.

Isso seria ótimo.
: +1:
Esperando por essa correção. Espero que chegue em 1.4

+1

Eu tenho outro caso de uso: eu preciso iniciar meus endpoints simulados com uma chamada $ http na inicialização (para armazenar alguns dados em cache) ...

+1

+1

apenas tropecei nisso também ...

@petebacondarwin acho que não há problema em continuar carregando todos os outros módulos, mas adie o início da navegação inicial.

alternativamente, o $ routeProvider pode oferecer um parâmetro de função configurável que deve adiar a renderização da rota inicial.

+1

+1

Aqui está uma possível solução alternativa: http://plnkr.co/edit/vi7mDjmD4NpZAoP7MVzr?p=preview
A ideia é que o Angular realmente dê a você a capacidade de criar seu próprio injetor a partir de um conjunto de módulos. Neste caso, adiei a compilação de $rootElement até que um monte de promessas ( resolves ) fossem resolvidas. Este é um POC e haveria uma série de outros sinos e apitos que seriam necessários para tornar esta produção pronta. Além de qualquer outra coisa, você precisaria detectar os erros nas resoluções, em vez de simplesmente engoli-los.

+1

Este é principalmente um guia para quem quer dar uma chance; Atualmente, o processo de bootstrap faz o seguinte:

  • Verificações de sanidade
  • Cria o produzido por $rootElement
  • Cria o injetor
  • Compila e vincula o $rootElement

Além disso, ao criar o injetor, as etapas são as seguintes:

  • Percorrendo a árvore do módulo de dependência e

    • Inicialização do módulo que registraria as constantes, valores, provedores e outras coisas do módulo

    • Executando as funções de configuração

    • Colete as funções run para mais tarde

  • Execute todas as funções run

Existem alguns pontos-chave:

  • Todos os blocos run são executados antes de $rootElement ser compilado
  • Não há ciclos de resumo no processo de criação do injetor, o primeiro ciclo de resumo ocorre durante a compilação inicial de $rootElement
  • $q resolve promessas durante um ciclo de resumo _somente_

Isto é:

  • Se houver um módulo que tem uma função run que retorna uma promessa e a promessa precisa ser resolvida antes do aplicativo iniciar, haverá ciclos de resumo antes da compilação inicial (isso pode interromper os aplicativos existentes)
  • Um bloco de configuração não pode retornar uma promessa porque uma função config é injetada com provedores, não com instâncias

Seja qual for a solução, precisa lidar com esses casos

+1
qualquer notícia?
Eu só quero carregar algumas configurações antes de o aplicativo realmente iniciar.

+1

Gostaria de carregar alguns dados assíncronos após o bootstrap quando todas as minhas fábricas estão ativas e antes de compilar.

@dagingaa : Acho que escolheria sua solução como alternativa! obrigado

  • 1

Atualize para @dagingaa : o loop for congela meus navegadores, não é bom ...

https://jsfiddle.net/tuxmachine/t4d63vnw/

Foi assim que resolvi para uma implementação de token OAuth, que exigia que uma chamada inicial ajax fosse resolvida antes de inicializar o restante do aplicativo.

Não funcionará se você tiver vários blocos de execução assíncrona, no entanto

+1

+1

+1

Já se passaram dois anos desde que o problema foi aberto e ainda não há uma boa solução

@vladmiller Existem soluções, mas talvez você não ache que sejam boas:

  • use ngRoute ou ui-router com resolve e coloque o código de inicialização do aplicativo dentro da rota de nível superior
  • crie seu próprio bootstrap assíncrono. consulte https://github.com/angular/angular.js/issues/4003#issuecomment -113842180
  • use o novo roteador de componente com $onActivate no componente de nível superior

Colocar trabalho de aplicativo não trivial dentro de blocos .run torna difícil o teste de unidade de seu código. Portanto, não é algo que queremos encorajar. Movendo isso para a caixa de gelo como algo que provavelmente não implementaremos.

@petebacondarwin, eu discordo de você; todos esperam que o angluar seja simples e intuitivo; em vez disso, você precisa implementar seu próprio módulo de bootstrap assíncrono ou módulo de bootstrap em um lugar diferente. Na minha opinião, isso torna o angular mais complexo.

Você também pode explicar o que quer dizer quando afirma que o código assíncrono em .run tornará o teste mais difícil?

Peço desculpas pelo meu comentário rude anterior.
Obrigado

@petebacondarwin Não consigo ver como isso torna difícil o teste. se você colocar o código de inicialização em um serviço, você pode apenas assistir / simular / comparar os resultados que você espera da simulação de back-end http, independentemente se ele está sendo executado dentro de um bloco .run ou não. ter código existindo fora do angular devido a soluções para a falta de execução assíncrona é o que torna quase impossível testar

Como está indo?

A solução

Como existem soluções alternativas e o suporte a blocos de execução assíncrona aumentaria a complexidade do bootstrap, não acho que implementaremos esse recurso.

jfcfxekzl5m
Recurso simples, mas muito difícil de implementar. 😕

+1 para este recurso

+1

+1

A solução

+1. :(

+1

+1

+1

+1

Não vamos fazer isso.

+100, todas as soluções alternativas são terríveis.

@Eduardo-Julio - não vamos implementar esse recurso, pois tornaria o bootstrap de aplicativos AngularJS muito mais complexo. Adicionar mais + s não ajudará.

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