Angular 網路連線狀態元件
在開發 Web 應用程式時,有時候我們需要獲取當前的網路狀態,然後根據不同的網路狀態顯示不同的提示訊息或顯示不同頁面內容。對於原生應用、混合應用或提供 JS-SDK 的第三方平臺來說,我們可以通過相關的 Network API 來獲取當前的網路連線狀態。但對於 Web 應用來說,雖然也有相關的Information_API" target="_blank" rel="nofollow,noindex">Network Information API ,但相容性並不是太好,具體的相容情況,可以參考Can I Use - netinfo 。
Network Information API
此 API 是由WICG
編輯的草案,目前可在 Chrome 61+ 的版本中使用。開發者可以通過navigator.connection
物件來訪問與當前網路連線相關的屬性:
- connection.type:返回當前 User Agent 的物理網路型別,可能的值為 “cellular”,”ethernet”,”wfi” 或 “none” 等;
- connection.downlink:返回基於最近觀察到的活動連線的有效頻寬(以 Mb/s 為單位);
- connection.rtt:返回基於最近觀察到的活動連線估計平均往返時間(以毫秒為單位);
- connection.saveData:如果使用者在其瀏覽器啟用 “reduced data mode” 模式,則返回 true;
- connection.effectiveType:返回有效的網路連線型別,可能的值為 slow-2g,2g,3g 或 4g。該值的是基於 rtt 和 downlink 的值測算出來的。
下面是網路連線型別的評估標準:
CT | Minimum RTT (ms) | Maximum downlink (Kbps) | Explanation |
---|---|---|---|
slow-2g | 2000 | 50 | The network is suited for small transfers only such as text-only pages. |
2g | 1400 | 70 | The network is suited for transfers of small images. |
3g | 270 | 700 | The network is suited for transfers of large assets such as high resolution images, audio, and SD video. |
4g | 0 | ∞ | The network is suited for HD video, real-time video, etc. |
講到這裡突然想起之前看到的一篇文章JS 檢測網路頻寬 ,有興趣的小夥伴可以瞭解一下。
開發網路連線元件
通過結合Network Information API 與 Angular,我們可以建立一個元件,實現根據不同網路連線速度渲染不同的內容。比如,當我們檢測到弱網路的時候,我們可以渲染一個佔位符或一個低解析度的圖片或視訊,從而提高頁面的載入速度。
首先,讓我們把連線變化事件封裝為一個 Observable 物件:
const connection$ = new Observable((observer) => { const { effectiveType } = navigator.connection; observer.next(effectiveType); const onConnectionChange = () => { const { effectiveType } = navigator.connection; observer.next(effectiveType); } navigator.connection.addEventListener('change', onConnectionChange) return () => { navigator.connection.removeEventListener('change', onConnectionChange); observer.complete(); } });
在頁面初始化和連線網路狀態發生變化的時候,可觀察的 connection$ 物件將會自動通知我們當前的網路連線狀態。
接下來,我們來建立 ConnectionComponent 元件和相關的 Connection 指令:
connection.component.ts
@Component({ selector: 'connection', template: ` <ng-template [ngTemplateOutlet]="fast.tpl" *ngIf="isFast"></ng-template> <ng-template [ngTemplateOutlet]="slow.tpl" *ngIf="!isFast"></ng-template> `, }) export class ConnectionComponent { isFast = true; @ContentChild(FastDirective) fast: FastDirective; @ContentChild(SlowDirective) slow: SlowDirective; private subscription: Subscription; ngOnInit() { const connection = navigator.connection; if (!connection) { // if the browser doesn't support it, we render the fast template return; } this.subscription = connection$ .subscribe((effectiveType: string) => { if (/slow-2g|2g|3g/.test(effectiveType)) { this.isFast = false; } else { this.isFast = true; } }) } ngOnDestroy() { this.subscription && this.subscription.unsubscribe(); } }
fast.directive.ts
@Directive({ selector: '[fast]' }) export class FastDirective { constructor(public tpl: TemplateRef<any>) { } }
slow.directive.ts
@Directive({ selector: '[slow]' }) export class SlowDirective { constructor(public tpl: TemplateRef<any>) { } }
在上面的示例中,ConnectionComponent 會根據effectiveType
屬性的值,然後顯示 slow 或 fast 指令例項所關聯的模板。現在我們來看一下如何使用:
<connection> <ng-container *fast> Fast connection - Render a video </ng-container> <ng-container *slow> Slow connection - Render a placeholder </ng-container> </connection>
正如前面提到的,基於Network Information API ,我們也可以實現一個簡單的指令,根據不同的網路狀態顯示不同解析度的圖片。
<img connection slowSrc="https://via.placeholder.com/350x150?text=slow" fastSrc="https://via.placeholder.com/350x150?text=fast">
對應的 connection 指令的具體實現如下:
import { Directive, Attribute, ElementRef } from '@angular/core'; @Directive({ selector: '[connection]' }) export class ConnectionDirective { constructor(@Attribute('slowSrc') private slowSrc, @Attribute('fastSrc') private fastSrc, private host: ElementRef<HTMLImageElement> ) { } ngOnInit() { const { effectiveType } = navigator.connection; let src; if (/slow-2g|2g|3g/.test(effectiveType)) { src = this.slowSrc; } else { src = this.fastSrc; } this.host.nativeElement.setAttribute('src', src) } }
檢視線上完整的示例:Stackblitz
總結
本文是在過完 “10·24 — 愛碼士” 節後,參考connection-aware-components-in-angular 這篇文章整理的。其中主要介紹了Network Information API 涉及的相關屬性及每個屬性的作用。對於使用 Ionic 或 Cordova 專案來說,可以使用cordova-plugin-network-information 這個庫來獲取網路資訊,有需要的小夥伴可以瞭解一下。