sincronas promesas funciones entre ejemplo ejecucion diferencia controlar await async asincronia asincrona anidadas javascript angularjs angular-ui-router async-await

javascript - funciones - promesas anidadas



El enrutador de UI angular no procesa la función de resolución cuando uso la función async/await? (2)

El problema es que angular espera una Promesa angular por lo que tu entonces funcionará pero tu espera no, puedes resolver esto usando una biblioteca como: https://www.npmjs.com/package/anguila-analy-animal o hacer una construcción como la que están demostrando aquí https://medium.com/@alSkachkov/using-async-await-function-in-angular-1-5-babel-6-387f7c43948c

¡Buena suerte con tu problema!

He intentado renderizar cierta plantilla relacionada con un estado y componente de acuerdo con este artículo

En mi proyecto que se ejecuta en dev-server todo funciona bien y cuando ejecuto $state.go("home") la plantilla del componente se carga como espero, pero cuando lo hago en un entorno de prueba, esto no funciona.

Antes, en las pruebas, cuando uso el "método antiguo" usando "plantilla" en vez de "componente" con ui-enrutador, ejecute $rootScope.$digest() fue suficiente para agregar la plantilla dentro de <div ui-view></div> pero usando esta nueva forma esto ya no funciona.

¿Qué estoy haciendo mal?

Editar : he estado tratando de entender profundamente el problema y veo que el problema está relacionado con la solicitud HTTP que se realizó. Tal vez está relacionado con la forma en que mi promesa se resuelve en la devolución de llamada de resolución usando async / await. Por favor, consulte el Servicio:

Servicio

export class TodoService { constructor($http, BASE_URL) { this.http = $http; this.url = `${BASE_URL}/todos` } async getTodos() { const apiResponse = await this.http.get(this.url) return apiResponse.data.todos } }

Enrutador

import ''@uirouter/angularjs'' export function routes($stateProvider, $locationProvider) { $locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: true, }) $stateProvider .state("home", { url: "/", component: "todoList", resolve: { todosList: TodoService => TodoService.getTodos() } }) }

Prueba

import { routes } from "routes" import { TodoListComponent } from "components/todoList.component" import { TodoService } from "services/todo.service" describe("TodoListComponent rendering and interaction on ''/'' base path", () => { let componentDOMelement let stateService beforeAll(() => { angular .module("Test", [ "ui.router" ]) .config(routes) .constant("BASE_URL", "http://localhost:5000/api") .component("todoList", TodoListComponent) .service("TodoService", TodoService) //I enable this for better logs about the problem .run([''$rootScope'',''$trace'', function($rootScope, $trace) { $trace.enable("TRANSITION") }]) }) beforeEach(angular.mock.module("Test")) beforeEach(inject(($rootScope, $compile, $state, $httpBackend) => { //build the scene //1st render the root element of scene: We needs a router view for load the base path let scope = $rootScope.$new() componentDOMelement = angular.element("<div ui-view></div>") $compile(componentDOMelement)(scope) scope.$digest() document.body.appendChild(componentDOMelement[0]) //This is a hack for jsdom before the $rootScope.$digest() call //2nd let''s create a fake server for intercept the http requests and fake the responses const todosResponse = require(`${__dirname}/../../stubs/todos_get.json`) $httpBackend .whenGET(/.+//todos/) .respond((method, url, data, headers, params) => { return [200, todosResponse] }) //3rd Let''s generate the basic scenario: Go at home state ("/" path) $state.go("home") $rootScope.$digest() $httpBackend.flush() })) it("Should be render a list", () => { console.log("HTML rendered") console.log(document.querySelectorAll("html")[0].outerHTML) }) })

El resultado HTML que no se renderiza

<html> <head> <style type="text/css"> @charset "UTF-8";[ng/:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate) { display:none !important; } ng/:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{ position:absolute; } </style> </head> <body><!-- uiView: --> </body> </html>

Además, rastreé el cambio de estado antes del HTML:

console.log node_modules/@uirouter/core/_bundles/ui-router-core.js:1276 Transition #0-0: Started -> "Transition#0( ''''{} -> ''home''{} )" console.log node_modules/@uirouter/core/_bundles/ui-router-core.js:1282 Transition #1-0: Ignored <> "Transition#1( ''''{} -> ''home''{} )" console.log node_modules/@uirouter/core/_bundles/ui-router-core.js:1313 Transition #1-0: <- Rejected "Transition#1( ''''{} -> ''home''{} )", reason: Transition Rejection($id: 0 type: 5, message: The transition was ignored, detail: "undefined")

Veo un problema en una transición pero no se dio ninguna razón.

=============================================== ======================

Edit 2 Finalmente encontramos el problema pero no puedo resolver el problema real . Creé una rama en mi proyecto para mostrar el problema. Esto está relacionado con la función async/await javascript:

export class TodoService { constructor($http, BASE_URL) { this.http = $http; this.url = `${BASE_URL}/todos` } //Interchange the comment on the getTodos method and run `npm run tdd` for see the problem: //When async/await doesn''t used, the html associated to the resolve in the // "/" route that used this service, the promise was resolved that expected. //The idea for this branch it''s research about the problem and propose a way //for we can use async/await on the production code and on the testing environment async getTodos() { const apiResponse = await this.http.get(this.url) return apiResponse.data.todos } // getTodos() { // return this.http.get(this.url).then(res => res.data.todos) // } }

El repositorio

Entonces mis nuevas Preguntas son:

  • ¿Por qué la forma en que uso la funcionalidad async / await no es compatible con la resolución del ui-router en el entorno de prueba pero en el código de producción funciona?
  • Tal vez está relacionado con $ httpBackend.flush () llamada?

Editar 3 El problema 3522 reportado en el repositorio angular del enrutador de UI


Esta es solo una suposición educada basada en mi comprensión de la forma en que los resolvedores trabajan y lo que hace ngMock . En su primer ejemplo, su resolve para getTodos no regresa hasta que se haya resuelto la promesa de $http , momento en el que extrae el valor de la respuesta y lo devuelve. Sin embargo, los resolvedores esperan un valor de $q.Promise como centinela para mantener el renderizado del enrutador hasta que se resuelva. En su código, dependiendo de cómo se haya transpuesto, es probable que la llamada de await y return no produzca el valor centinela correcto, por lo que se trata como una respuesta síncrona.

Una forma de probarlo sería solicitar la resolve -er en el controlador de su componente todolist e inspeccionar el valor. Apuesto a que NO es una $q.Promise , aunque podría ser una Promesa nativa.

Sin embargo, al usar resolve , simplemente encadene la Promesa agregando a then y then devuélvala. El enrutador se encargará del resto.

¡O mejor, pasa a Observables! (/ yo patos tomates entrantes)