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)
// }
}
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)