6-6.Angular 入門教學 - 預先載入資料Resolve

Angular 入門教學


今天我們終於要來解決很久之前提到的todo代辦事項,剛進入要等一下資料才會出來會造成使用者體驗不佳的問題

反應時間短,可能還行,但如果要等個幾秒,那就有可能造成使用者誤會

想說網站是沒資料,還是當掉了呢?

而網路資料本來就需要時間從伺服器取回來,所以等待時間是不可避免的

那這時候就要用其他策略性作法來解決這個體驗的問題

這篇要來教一個策略,就是使用預載資料的做法,就是將資料載入完之後,畫面在顯示

如此當畫面出現的時候,資料也準備好了所以會同時會在畫面上,這樣就不會剛進去時資料還沒出來,過一陣子才又冒出來


首先先下一個產生resolve的指令

ng g r todo

那這會產生resolve的基本格式,這是作為angular的預載機制的一個檔案類型

這邊我們需要依賴注入TodoApiService,這裡也可以發現為什麼要把api的部分切成service,因為很多地方可能都會用到

constructor(private todoApiService:TodoApiService){}

那依賴注入TodoApiService要做什麼?就是要在resolve這邊先取得todo的資料

整個寫完的程式碼如下

import { Todo } from './../@models/todo.model';
import { TodoApiService } from './../@services/todo-api.service';
import { Injectable } from '@angular/core';
import {
  Router, Resolve,
  RouterStateSnapshot,
  ActivatedRouteSnapshot
} from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class TodoResolver implements Resolve<Todo[]> {

  constructor(private todoApiService: TodoApiService, private todoService: TodoService) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Todo[]> {
    const id = route.paramMap.get('id') as string;
    this.todoService.gid = id;
    return this.todoApiService.取得資料(id);
  }

}

這邊用到上一篇的技巧,因為我們現在有不同的代辦事項

所以要先取得id後才能撈取指定的代辦事項,而在resolve中一樣可以取得id,用法如上

取得id後,我們就可以繼續取得指定代辦事項

最後我們再到todo-routing.module.ts,加上預載資料的設定

const routes: Routes = [
  { path: 'list', component: TodoListComponent },
  {
    path: 'content/:id',
    children: [
      {
        path: ':action',
        component: TodoContentComponent,
        resolve: { todoList: TodoResolver }
      },
      { path: '', redirectTo: 'All', pathMatch: 'full' }
    ]

  },
  { path: '', redirectTo: 'list', pathMatch: 'full' }
];

就是在該路由設定中,多一個resolve,後面的todoList是自訂的變數,隨後放的是剛剛寫的TodoResolver

這樣在進入這一頁前,會先執行TodoResolver,並且在進入TodoContentComponent後,就可以拿到預載完的資料

那要怎麼取得呢?我們就到todo-content.component.ts中來取得

constructor(private todoService: TodoService,
  private route: ActivatedRoute) { }
  

ngOnInit() {
  this.todoService.todoDataList = [];
  this.route.data.subscribe(data=>{
   this.todoService.todoDataList = data['todoList'];
   this.todoService.ready();
  });
}

可以使用this.route.data.subscribe來取得todoDataList的資料,如上

回到畫面上看一下效果有沒有出現

可以發現,我們這次進去後,畫面就已經有資料了,不會再過一陣子才出來

那這邊的話還有另一個寫法

ngOnInit() {
  this.todoService.todoDataList = this.route.snapshot.data['todoList'];
}

snapshot一樣可以取得,但一樣會有上一篇的問題,如果是相同的component換頁,這行不會再執行第二次,要注意一下

最後todo-list這邊也是需要設置預先載入,就留給大家練習


到這邊,相信一定會有人覺得哪裡怪怪的

沒錯,就是預載資料本身這件事就有違和之處

我們只是將等待時間往前移了,本來等待資料在進入頁面之後,變成移到切換頁面之前

那這樣不就跟MPA網站的一樣,是等待資料全部準備好,才會進入下一頁

那體驗感不就跟MPA又變成一樣了嗎?不能馬上切換畫面過去

沒錯,在頁面需要資料的情況下,我們還是得花時間下載資料才行,只有在不需要資料的情況下,畫面才能直接切換過去

但大部分的頁面都是動態頁面,資料都是動態的,所以基本上都要進去之後才下載

雖然流程似乎跟MPA一樣了,但其實效能上SPA還是大勝

我們仔細觀察,MPA是整個網頁、JS、CSS和相關圖片檔案都做重新載入

但我們SPA只有載入資料而已,所以雖然載入動態頁面的流程變得差不多

不過兩者下載的資料量跟處理,可是天差地遠,SPA雖然在載資料的時候一樣要等,但等的時間絕對是贏過MPA

最後,我們還有一個地方要解決,就是當我們按下需要預載的頁面時,畫面會沒有任何動作,但其實正在預載資料,載完才會切換過去

不過這時就會讓使用者感到疑惑?是系統當了,還是系統效能太差,怎麼卡住了?

所以,我們在這邊還需要自己設計一個載入條,告知使用者,有收到換頁要求,正在載入中喔

那下一篇,就會來示範載入條要怎麼做


回到策略面選擇問題

其實並非所有情況都要預先載入,視情況我們有些資料也是可以在畫面出現之後,在慢慢載入

那我個人認為,速度在3秒內,畫面必要資料,可以考慮預先載入

那須要等很久的資料或非必要資料,像fb的貼文,就可以等到畫面出來之後再載入就好,那當然此類資料也要額外設置提示訊息,不能讓使用者看著一片空白的畫面

用前端框架,真的需要考慮很多事情,做很多使用者體驗的設計,並且要視情況選擇不同的顯示策略

所以前端常常花的時間都不是功能面,而是顯示面的設計反而會占掉大多數的開發時間

如果什麼都不做,其實也很快可以開發完,但既然用了前端框架,那就是要做~~~

 

範例檔:下載




Copyright © 凱哥寫程式 2022 | Powered by TalllKai ❤