专栏首页全栈修仙之路Angular 网络连接状态组件

Angular 网络连接状态组件

在开发 Web 应用程序时,有时候我们需要获取当前的网络状态,然后根据不同的网络状态显示不同的提示消息或显示不同页面内容。对于原生应用、混合应用或提供 JS-SDK 的第三方平台来说,我们可以通过相关的 Network API 来获取当前的网络连接状态。但对于 Web 应用来说,虽然也有相关的 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 这个库来获取网络信息,有需要的小伙伴可以了解一下。

参考资源

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在前端 Network 还能这样玩

    这几年手机和网络已经是大多数人生活中的必需品,其中有很多人,比如我家”超哥“,她每次到一个新的环境中一般开口都会来一句,”请问你家有 WIFI 么,密码是多少?...

    阿宝哥
  • Angular 自定义管道

    本文将使用 UltimateAngular/angular-pro-src 中的示例,来一步步介绍自定义管道的相关知识。在该示例中,我们将定义一个 FileSi...

    阿宝哥
  • TypeScript 设计模式之抽象工厂

    在现实生活中,工厂是负责生产产品的,比如牛奶、面包或礼物等,这些产品满足了我们日常的生理需求。

    阿宝哥
  • Android HttpURLConnection 工具类(封装)

    随着 Okhttp 等框架的横空出世,最原生的网络请求已经退出历史舞台,但是有时候还是需要这种方式来请求的,因此我把它封装成一个工具类使用,需要的小伙伴直接复制...

    IT大飞说
  • Java调用飞信API

    梦_之_旅
  • ActiveMQ NMS使用过程中的一点经验

      最近,项目中使用到了ActiveMQ获取第三方推送过来的数据。具体背景是:公司需要监控全国各地车辆实时运行的GPS数据,但监控本身不是公司做的,而是交给第三...

    guokun
  • 腾讯云存储专家深度解读基于Ceph对象存储的混合云机制

      毫无疑问,乘着云计算发展的东风,Ceph已经是当今最火热的软件定义存储开源项目。如下图所示,它在同一底层平台之上可以对外提供三种存储接口,分别是文件存储、对...

    用户1532637
  • Android开发笔记(一)像素的单位

    老子曾说“天下难事必作于易,天下大事必作于细”,其实Android开发也是如此。博主一开始学android的时候,对像素单位不知其所以然,只知一根筋的填数字...

    用户4464237
  • JDBC第二篇【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】(修订版)

    PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单

    Java3y
  • P2051 [AHOI2009]中国象棋

    题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大...

    attack

扫码关注云+社区

领取腾讯云代金券