logo头像
书院的十三先生

Angular性能优化与集成GraphQL

一、Angular性能优化点

Angular优化只是前端优化的一个子集,本篇仅涉及Angular相关的优化:

1. 合理划分特性模块

在一些项目中所有组件都放到一个模块中,特别是很多组件的初始化逻辑放在组件构造器或者ngOnInit方法中,这样会导致首次加载很慢,而将组件按照相关性划分到不同的特性模块,并使用懒加载方式加载,就能减少首次初始化的时间,提高性能。

2. 选择合适的生命周期钩子

有的时候,我们习惯性的将一些公共方法放到构造器或者ngOnInit方法中,例如给API中心上报组件调用信息,这样也会导致看上去页面首开性能很差,因此,对于不影响界面展现的方法应放到ngAfterViewInit方法中。

3. 按需调用组件初始化方法

当组件包含子组件时,我们会在ngOnInit中调用组件初始化的方法,哪怕这个组件在初次展现时并不可见,例如多个tab页,每个tab页是一个独立的子功能。如果子组件影响了性能,应在子组件可见时再调用初始化方法,而不是放在ngOnInit中。

4. 合并多个服务请求

chrom浏览器对一个域名一次并发的请求数最大是6个,如果超过6个就会排队等待,所以对于超过6个请求的可以考虑合并,合并包括图片合并、js,css文件合并,后端服务合并。一般来说现有的前端框架在打包时已经将js,css文件合并,图片合并和后端服务合并需要自行实现。

二、Angular集成GraphQL

前面提到提高性能的其中一个方法是合并多个服务请求,对此可以要求后端GG重新封装一个聚合服务,通常这也没什么问题,而查询需求可能合并千变万化,当服务很多时总是要求后端GG封装新的聚合服务就不是那么顺利了,为了减少前后端的耦合,可以集成GraphQL来解决这个问题,GraphQL可以在一次查询中同时请求多个后端服务,将多个服务的查询结果聚合后返回。

三、集成样例

这个例子的后端服务参考:Web应用全栈之旅-Spring篇(四)集成GraphQL。

1. 安装apollo-angular

ng add apollo-angular

2. 安装graphql apollo-client相关的的模块

npm install apollo-client apollo-cache-inmemory apollo-angular-link-http apollo-angular graphql-tag graphql  --save

3. 修改连接地址

修改graphql.module.ts中的 uri。

const uri = 'http://localhost:7000/graphql'; // <-- add the URL of the GraphQL server here
export function createApollo(httpLink: HttpLink) {
  return {
    link: httpLink.create({uri}),
    cache: new InMemoryCache(),
  };
}

4. 查询例子(不带变量)

代码如下:

query() {
  let query = gql`
    query {
      findBook(id:1) {
        name
        publisher
        author{
          id
        }        
      }
      findDogByName(name:"xiaofei") {
        name
        age
        gender
      }
    }
  `;

  this.apollo
  .watchQuery({
    query: query,
  })
  .valueChanges.subscribe((result:any)=>{
        console.log(result)
  });
}

可以看到在一个请求中调用了后端的两个服务。
请求包如下:

{
    "operationName": null,
    "variables": {},
    "query": "{\n  findBook(id: 1) {\n    name\n    publisher\n    author {\n      id\n      __typename\n    }\n    __typename\n  }\n  findDogByName(name: \"xiaofei\") {\n    name\n    age\n    gender\n    __typename\n  }\n}\n"
}

可以看到operationName为null,variables中没有变量传入。
应答包如下:

{
    "data": {
        "findBook": {
            "name": "Java 8实战",
            "publisher": "电子工业出版社",
            "author": {
                "id": 1,
                "__typename": "Author"
            },
            "__typename": "Book"
        },
        "findDogByName": {
            "name": "xiaofei",
            "age": 3,
            "gender": "male",
            "__typename": "Dog"
        }
    }
}

5. 查询例子(带变量)

代码如下:

query1() {
    let query = gql`
      query myoperation($id:Int, $name:String!) {
        findBook(id:$id) {
          name
          publisher
          author{
            id
          }        
        }
        findDogByName(name:$name) {
          name
          age
          gender
        }
      }
    `;
    this.apollo
    .watchQuery({
      query: query,
      variables: {
        id: 1,
        name: "xiaofei",
      },
    })
    .valueChanges.subscribe((result:any)=>{
          console.log(result)
    });

其中myoperation是operationName,可自行定义,目的是为了传入变量。
请求包:

{
    "operationName": "myoperation",
    "variables": {
        "id": 1,
        "name": "xiaofei"
    },
    "query": "query myoperation($id: Int, $name: String!) {\n  findBook(id: $id) {\n    name\n    publisher\n    author {\n      id\n      __typename\n    }\n    __typename\n  }\n  findDogByName(name: $name) {\n    name\n    age\n    gender\n    __typename\n  }\n}\n"
}

可以看到operationName和variables都有值了。

end.

apollographql官网地址: https://www.apollographql.com/docs/angular/


站点: http://javashizhan.com/


微信公众号: