javascript - 当我使用异步/等待功能时,Angular UI 路由器不处理解析功能?

标签 javascript angularjs angular-ui-router async-await

我一直在尝试根据此 article 呈现与状态和组件相关的某些模板

在我的开发服务器下运行的项目中,一切正常,当我执行 $state.go("home") 时组件模板按照我的预期加载,但是当我在测试环境中执行此操作时,这不起作用。

之前,在测试中,当我使用“旧方法”使用"template"而不是“组件”和 ui-router 时,执行 $rootScope.$digest()足以在 <div ui-view></div> 中添加模板但是使用这种新方法就不再有效了。

我做错了什么?

编辑:我一直在努力深入理解这个问题,我发现这个问题与完成的 HTTP 请求有关。也许这与我的 promise 使用 async/await 在解析回调上解析的方式有关。请检查服务:

服务

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

路由器

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

测试

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

未渲染的HTML结果

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

此外,我在 HTML 之前跟踪了 stateChange:

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

我发现转换存在问题,但没有给出原因。

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

编辑 2 最后我们找到了问题,但我无法找出真正的问题。我在我的项目中创建了一个分支来显示问题。这与 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)
    // }
}

The repository

所以我的新问题是:

  • 为什么我使用 async/await 功能的方式在测试环境中与 ui-router 解析不兼容,但在生产代码中却有效?
  • 可能与 $httpBackend.flush() 调用有关?

编辑 3 问题3522在 Angular UI 路由器存储库中报告

最佳答案

问题是 Angular 需要一个 Angular Promise,这就是为什么你的 then 会工作但你的 await 不会,你可以通过使用像这样的库来解决这个问题:https://www.npmjs.com/package/angular-async-await或者像他们在这里展示的那样 build 一个建筑https://medium.com/@alSkachkov/using-async-await-function-in-angular-1-5-babel-6-387f7c43948c

祝你好运!

关于javascript - 当我使用异步/等待功能时,Angular UI 路由器不处理解析功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45863496/

相关文章:

javascript - Angular Directive(指令)无法识别属性

javascript - Angular UI Modal Controller 未暴露给指令

javascript - Angular (ui-router) 路由无法完全正常工作?无法直接访问 url 而不通过基本 url

Javascript/JQuery 迭代表行和单元格,并将选中的复选框的属性输出到控制台

javascript - 来自 JavaScript 的 HTTP 请求使用包含 header 的原始消息

java - 丰富的面孔 : how to add static text beside value on InputNumberSlider tooltip?

javascript - 当指令被销毁时,attrs.$observe 是否取消注册?

javascript - 如何在 Angular 4 上获取引荐来源网址?

javascript - 将 AngularJS Controller 分离到单独的文件中

javascript - 如何在大小取决于不同移动屏幕尺寸的 iFrame 中居中对齐内容?