promise 和 Observable 的区别-阿里云开发者社区

开发者社区> 开发者小助手-bz5> 正文

promise 和 Observable 的区别

简介: promise 和 Observable 的区别
+关注继续查看

StackOverflow 上的讨论:What is the difference between Promises and Observables?

得赞最高的一个回答:1777 赞

image.png

当异步操作完成或失败时,Promise 会处理单个事件。


注意:有 Promise 库支持 cancellation 操作,但 ES6 Promise 到目前为止还不支持。


Observable

一个 Observable 就像一个 Stream(在许多语言中),允许传递零个或多个事件,其中为每个事件调用回调。


通常 Observable 比 Promise 更受欢迎,因为它提供了 Promise 的特性等等。使用 Observable,您是否要处理 0、1 或多个事件并不重要。您可以在每种情况下使用相同的 API。


Observable 还比 Promise 具有可取消的优势。如果不再需要对服务器的 HTTP 请求或其他一些昂贵的异步操作的结果,Observable 的订阅允许取消订阅,而 Promise 最终会调用成功或失败的回调,即使你不这样做不再需要通知或它提供的结果。


虽然 Promise 会立即启动,但 Observable 只有在您订阅它时才会启动。这就是为什么 Observable 被称为懒惰的原因。


Observable 提供了 map、forEach、reduce 等运算符,用法类似于数组。


还有一些强大的操作符,如 retry() 或 replay() 等,它们通常非常方便。


延迟执行允许在通过订阅执行 observable 之前建立一系列操作符,以进行更具声明性的编程。


排名第二的回答:374 赞

image.png

举例说明。


Angular 使用 Rx.js Observables 而不是 promises 来处理 HTTP。


假设您正在构建一个搜索功能,该功能应在您键入时立即显示结果。 听起来很熟悉,但这项任务会带来很多挑战。


我们不想在用户每次按下一个键时都访问服务器端点,如果这样做的话,服务器会被大量的 HTTP 请求淹没。 基本上,我们只想在用户停止输入后触发 HTTP 请求,而不是每次击键时触发。


对于后续请求,不要使用相同的查询参数访问搜索端点。


处理无序响应。 当我们同时有多个请求进行中时,我们必须考虑它们以意外顺序返回的情况。 想象一下,我们首先键入 computer,停止,发出请求,然后键入 car,停止,发出请求。 现在我们有两个正在进行的请求。 不幸的是,携带结果给computer 的请求在携带结果给 car 的请求之后返回。


首先看如何用 promise 实现这个需求。当然,上文提到的所有边界情况都没有处理。


wikipedia-service.ts:

import { Injectable } from '@angular/core';

import { URLSearchParams, Jsonp } from '@angular/http';

@Injectable()

export class WikipediaService {

 constructor(private jsonp: Jsonp) {}

 search (term: string) {

   var search = new URLSearchParams()

   search.set('action', 'opensearch');

   search.set('search', term);

   search.set('format', 'json');

   return this.jsonp

               .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search })

               .toPromise()

               .then((response) => response.json()[1]);

 }

}

我们正在注入 Jsonp 服务,以使用给定的搜索词对 Wikipedia API 发出 GET 请求。 请注意,我们调用 toPromise 是为了从 Observable 到 Promise。 最终以 Promise 作为我们搜索方法的返回类型。


app.ts 的实现:

// check the plnkr for the full list of imports

import {...} from '...';

@Component({

 selector: 'my-app',

 template: `

   

     

Wikipedia Search

     

     

           

  • {{item}}
  •      

       

     `

    })

    export class AppComponent {

     items: Array;

     constructor(private wikipediaService: WikipediaService) {}

     search(term) {

       this.wikipediaService.search(term)

                            .then(items => this.items = items);

     }

    }

    这里也没什么惊喜。 我们注入我们的 WikipediaService 并通过搜索方法向模板公开它的功能。 该模板简单地绑定到 keyup 并调用 search(term.value)。


    我们解开 WikipediaService 的搜索方法返回的 Promise 的结果,并将其作为一个简单的字符串数组公开给模板,这样我们就可以让 *ngFor 循环遍历它并为我们构建一个列表。


    Where Observables really shine

    让我们更改我们的代码,不要在每次击键时敲击端点,而是仅在用户停止输入 400 毫秒时发送请求


    为了揭示这样的超能力,我们首先需要获得一个 Observable ,它携带用户输入的搜索词。 我们可以利用 Angular 的 formControl 指令,而不是手动绑定到 keyup 事件。 要使用此指令,我们首先需要将 ReactiveFormsModule 导入到我们的应用程序模块中。


    app.ts:

    import { NgModule } from '@angular/core';

    import { BrowserModule } from '@angular/platform-browser';

    import { JsonpModule } from '@angular/http';

    import { ReactiveFormsModule } from '@angular/forms';

    @NgModule({

     imports: [BrowserModule, JsonpModule, ReactiveFormsModule]

     declarations: [AppComponent],

     bootstrap: [AppComponent]

    })

    export class AppModule {}

    导入后,我们可以在模板中使用 formControl 并将其设置为名称“term”。

    在我们的组件中,我们从@angular/form 创建了一个 FormControl 的实例,并将其公开为组件上名称 term 下的一个字段。


    在幕后,term 自动公开一个 Observable 作为我们可以订阅的属性 valueChanges。 现在我们有了一个 Observable,获得用户输入就像在我们的 Observable 上调用 debounceTime(400) 一样简单。 这将返回一个新的 Observable,它只会在 400 毫秒内没有新值出现时才发出新值。

    export class App {

     items: Array;

     term = new FormControl();

     constructor(private wikipediaService: WikipediaService) {

       this.term.valueChanges

                 .debounceTime(400)        // wait for 400ms pause in events

                 .distinctUntilChanged()   // ignore if next search term is same as previous

                 .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));

     }

    }

    对我们的应用程序已经显示结果的搜索词发出另一个请求将是一种资源浪费。 为了实现所需的行为,我们所要做的就是在我们调用 debounceTime(400) 之后立即调用 distinctUntilChanged 运算符。

    Observable 和 promise 的比较:

    image.png

    版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

    相关文章
    高校学生在家实践ECS弹性云服务器
    简单谈谈我这几周使用ECS弹性云服务器的体验感
    6 0
    01_spring_ 简介| 学习笔记
    快速学习01_spring_ 简介
    10 0
    02_spring_ioc| 学习笔记
    快速学习02_spring_ioc
    4 0
    微服务架构 | *2.3 Spring Cloud 启动及加载配置文件源码分析(以 Nacos 为例)
    Spring Cloud 要实现统一配置管理,需要解决两个问题:如何获取远程服务器配置和如何动态更新配置;在这之前,我们先要知道 Spring Cloud 什么时候给我们加载配置文件;
    3 0
    03_spring_ioc 实现| 学习笔记
    快速学习03_spring_ioc 实现
    5 0
    昨天你用的 YYYY-MM-dd 被 CTO 捶了吗?
    下班回家的路上,习惯性打开 群聊 ,不是为了解答问题,而是不想错过任何一个装 x 的机会。这不,就有胖友聊到一个经典的“神坑”:错误使用 YYYY-MM-dd 格式化时间,导致生产翻车。
    5 0
    xshell+阿里云linux+vue+mysql开发练习
    这篇文章记录了我在阿里云进行Linux基础学习的过程,以及根据阿里云进行一些简单的开发实践。
    9 0
    高校学生在家实践ECS弹性云服务器
    简单谈谈我这几周使用ECS弹性云服务器的体验感
    5 0
    05_spring_ 配置文件| 学习笔记
    快速学习05_spring_ 配置文件
    7 0
    飞天加速计划·高校学生在家实践
    我用阿里云服务器的一些心得
    18 0
    2497
    文章
    0
    问答
    来源圈子
    更多
    + 订阅
    文章排行榜
    最热
    最新
    相关电子书
    更多
    《2021云上架构与运维峰会演讲合集》
    立即下载
    《零基础CSS入门教程》
    立即下载
    《零基础HTML入门教程》
    立即下载