下载APP 编程狮,随时随地学编程
返回 首页

Angular9 中文教程

Angular9 与其他技术比较

可观察对象与其它技术的比较

你可以经常使用可观察对象(Observable)而不是承诺(Promise)来异步传递值。 类似的,可观察对象也可以取代事件处理器的位置。最后,由于可观察对象传递多个值,所以你可以在任何可能构建和操作数组的地方使用可观察对象。

在这些情况下,可观察对象的行为与其替代技术有一些差异,不过也提供了一些显著的优势。下面是对这些差异的详细比较。

可观察对象 vs. 承诺

可观察对象经常拿来和承诺进行对比。有一些关键的不同点:

  • 可观察对象是声明式的,在被订阅之前,它不会开始执行。承诺是在创建时就立即执行的。这让可观察对象可用于定义那些应该按需执行的菜谱。

  • 可观察对象能提供多个值。承诺只提供一个。这让可观察对象可用于随着时间的推移获取多个值。

  • 可观察对象会区分串联处理和订阅语句。承诺只有 .then() 语句。这让可观察对象可用于创建供系统的其它部分使用而不希望立即执行的复杂菜谱。

  • 可观察对象的 subscribe() 会负责处理错误。承诺会把错误推送给它的子承诺。这让可观察对象可用于进行集中式、可预测的错误处理。

创建与订阅

  • 在有消费者订阅之前,可观察对象不会执行。subscribe() 会执行一次定义好的行为,并且可以再次调用它。每次订阅都是单独计算的。重新订阅会导致重新计算这些值。

    Path:"src/observables.ts (observable)" 。

    // declare a publishing operation
    const observable = new Observable<number>(observer => {
      // Subscriber fn...
    });
    
    // initiate execution
    observable.subscribe(() => {
      // observer handles notifications
    });
  • 承诺会立即执行,并且只执行一次。当承诺创建时,会立即计算出结果。没有办法重新做一次。所有的 then 语句(订阅)都会共享同一次计算。

    Path:"src/promises.ts (promise)" 。

    // initiate execution
    const promise = new Promise<number>((resolve, reject) => {
      // Executer fn...
    });
    
    promise.then(value => {
      // handle result here
    });

串联

  • 可观察对象会区分各种转换函数,比如映射和订阅。只有订阅才会激活订阅者函数,以开始计算那些值。

    Path:"src/observables.ts (chain)" 。

    observable.pipe(map(v => 2 * v));
  • 承诺并不区分最后的 .then() 语句(等价于订阅)和中间的 .then() 语句(等价于映射)。

    Path:"src/promises.ts (chain)" 。

    promise.then(v => 2 * v);

可取消

  • 可观察对象的订阅是可取消的。取消订阅会移除监听器,使其不再接受将来的值,并通知订阅者函数取消正在进行的工作。

    Path:"src/observables.ts (unsubcribe)" 。

    const subscription = observable.subscribe(() => {
      // observer handles notifications
    });
    
    subscription.unsubscribe();
  • 承诺是不可取消的。

错误处理

  • 可观察对象的错误处理工作交给了订阅者的错误处理器,并且该订阅者会自动取消对这个可观察对象的订阅。

    Path:"src/observables.ts (error)" 。

    observable.subscribe(() => {
      throw Error('my error');
    });
  • 承诺会把错误推给其子承诺。

    Path:"src/promises.ts (error)" 。

    promise.then(() => {
      throw Error('my error');
    });

速查表

下列代码片段揭示了同样的操作要如何分别使用可观察对象和承诺进行实现。

操作 可观察对象 承诺
创建 new Observable((observer) => { observer.next(123); }); new Promise((resolve, reject) => { resolve(123); });
转换 obs.pipe(map((value) => value * 2)); promise.then((value) => value * 2);
订阅 sub = obs.subscribe((value) => { console.log(value) }); promise.then((value) => { console.log(value); })
取消订阅 sub.unsubscribe(); 承诺被解析时隐式完成。

可观察对象 vs. 事件 API

可观察对象和事件 API 中的事件处理器很像。这两种技术都会定义通知处理器,并使用它们来处理一段时间内传递的多个值。订阅可观察对象与添加事件处理器是等价的。一个显著的不同是你可以配置可观察对象,使其在把事件传给事件处理器之前先进行转换。

使用可观察对象来处理错误和异步操作在 HTTP 请求这样的场景下更加具有一致性。

下列代码片段揭示了同样的操作要如何分别使用可观察对象和事件 API 进行实现。

  1. “创建与取消”操作。

    • 可观察对象。
    // Setup
    let clicks$ = fromEvent(buttonEl, ‘click’);
    // Begin listening
    let subscription = clicks$
      .subscribe(e => console.log(‘Clicked’, e))
    // Stop listening
    subscription.unsubscribe();
    • 事件 API。
    function handler(e) {
      console.log(‘Clicked’, e);
    }
    // Setup & begin listening
    button.addEventListener(‘click’, handler);
    // Stop listening
    button.removeEventListener(‘click’, handler);
  2. 配置操作。

    • 可观察对象。

    监听按键,提供一个流来表示这些输入的值。

    fromEvent(inputEl, 'keydown').pipe(
      map(e => e.target.value)
    );
    • 事件 API。

    不支持配置。

    element.addEventListener(eventName, (event) => {
      // Cannot change the passed Event into another
      // value before it gets to the handler
    });
  3. 订阅操作。

    • 可观察对象。
    observable.subscribe(() => {
      // notification handlers here
    });
    • 事件 API。
    element.addEventListener(eventName, (event) => {
      // notification handler here
    });

可观察对象 vs. 数组

可观察对象会随时间生成值。数组是用一组静态的值创建的。某种意义上,可观察对象是异步的,而数组是同步的。 在下面的例子中, 符号表示异步传递值。

  1. 给出值。

    • 可观察对象。
    obs: ➞1➞2➞3➞5➞7
    obsB: ➞'a'➞'b'➞'c'
    • 数组。
    arr: [1, 2, 3, 5, 7]
    arrB: ['a', 'b', 'c']
  2. concat()

    • 可观察对象。
    concat(obs, obsB)
    ➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'
    • 数组。
    arr.concat(arrB)
    [1,2,3,5,7,'a','b','c']
    1. filter()
    • 可观察对象。
    obs.pipe(filter((v) => v>3))
    ➞5➞7
    • 数组。
    arr.filter((v) => v>3)
    [5, 7]
    1. find()
    • 可观察对象。
    obs.pipe(find((v) => v>3))
    ➞5
    • 数组。
    arr.find((v) => v>3)
    5
    1. findIndex()
    • 可观察对象。
    obs.pipe(findIndex((v) => v>3))
    ➞3
    • 数组。
    arr.findIndex((v) => v>3)
    3
    1. forEach()
    • 可观察对象。
    obs.pipe(tap((v) => {
      console.log(v);
    }))
    1
    2
    3
    5
    7
    • 数组。
    arr.forEach((v) => {
      console.log(v);
    })
    1
    2
    3
    5
    7
    1. map()
    • 可观察对象。
    obs.pipe(map((v) => -v))
    ➞-1➞-2➞-3➞-5➞-7
    • 数组。
    arr.map((v) => -v)
    [-1, -2, -3, -5, -7]
    1. reduce()
    • 可观察对象。
    obs.pipe(reduce((s,v)=> s+v, 0))
    ➞18
    • 数组。
    arr.reduce((s,v) => s+v, 0)
    18
目录

Anguler9 中文教程总览

Angular9 简介

Angular9 快速上手

Angular9 搭建环境

Angular9 基本概念

Angular9 架构概览
Angular9 模块简介
Angular9 组件简介
Angular9 服务与 DI 简介
Angular9 技能扩展

Angular9 英雄指南

Hero guide 简介
Hero guide 创建项目
Hero guide 编辑器
Hero guide 显示列表
Hero guide 创建特性组件
Hero guide 添加服务
Hero guide 添加应用内导航
Hero guide 从服务器端获取数据
Angular9 词汇表

Angular9 基础知识

Angular9 组件与模板

Angular9 显示数据
Angular9 模板语法
Angular9 用户输入
Angular9 属性型指令
Angular9 结构型指令
Angular9 管道
Angular9 生命周期钩子
Angular9 组件交互
Angular9 组件样式
Angular9动态组件
Angular9 元素

Angular9 表单与用户输入

Angular9 表单简介
Angular9 响应式表单
Angular9 验证表单输入
Angular9 构建动态表单

Angular9 Observable 与 RxJS

Angular9 Observable 概览
Angular9 RxJS库
Angular9 可观察对象
Angular9 可观察对象用法实战
Angular9 与其他技术比较

Angular9 NgModule

Angular9 NgModules 简介
Angular9 JS 模块与 NgMoudule 比较
Angular9 以根模块启动应用
Angular9 常用模块
Angular9 特性模块分类
Angular9 入口组件
Angular9 特性模块
Angular9 提供依赖
Angular9 单例服务
Angular9 惰性加载
Angular9 共享特性模块
Angular9 NgModule API
Angular9 NgModule 常见问题

Angular9 依赖注入

Angular9 依赖注入
Angular9 多级注入器
Angular9 DI 提供者
Angular9 DI 实战
Angular9 浏览组件树

Angular9 通过 HTTP 访问服务器

Angular9 准备工作
Angular9 请求数据
Angular9 处理请求错误
Angular9 向服务器发送数据
Angular9 配置 URL 参数
Angular9 拦截请求和响应
Angular9 跟踪和显示请求进度
Angular9 防抖优化
Angular9 XSRF 防护
Angular9 测试 HTTP 请求

Angular9 路由与导航

Angular9 生成路由应用
Angular9 定义基本路由
Angular9 获取路由信息
Angular9 设置通配符路由
Angular9 嵌套路由
Angular9 相对路径
Angular9 访问查询参数与片段

Angular9 路由器教程

Route 起步
Route 路由模块
Route特性区
Route 子路由
Route 路由守卫
Route 异步路由
Angular9 LocationStrategy 和浏览器网址样式
Angular9 <base href>
Angular9 路由器参考手册

Angular9 安全

Angular9 防范跨站脚本(XSS)攻击
Angular9 信任安全值
Angular9 HTTP级别漏洞

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }