首页 文章

承诺vs Observable

提问于
浏览
932

有人可以解释Angular中 PromiseObservable 之间的区别吗?

每个例子都有助于理解这两种情况 . 在什么情况下我们可以使用每个案例?

20 回答

  • 0

    我相信所有其他答案都应该清除你的疑虑 . 不过,我只是想补充说,observables是基于函数式编程的,我发现它附带的函数非常有用,如map,flatmap,reduce,zip . Web实现的一致性,特别是当它依赖于API请求时,是一种残酷的改进 .

    我强烈推荐this documentation,因为它是reactiveX的官方文档,我发现它是最清晰的 .

    如果你想进入observables我会建议这个3部分帖子:http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

    虽然它适用于RxJava,但概念是相同的,并且它的解释非常好 . 在reactiveX文档中,您具有每个函数的等价性 . 你必须寻找RxJS .

    我希望这有帮助,我只是想在这里做出贡献 . :)

  • 16

    PromisesObservables 都为我们提供了抽象,帮助我们处理应用程序的 asynchronous 性质 . @Günter和@Relu清楚地指出了它们之间的区别 .

    由于代码段值得千言万语,让我们通过下面的示例更容易理解它们 .

    感谢@Christoph Burgdorf的精彩文章


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

    假设您正在构建一个 search function ,它应该在您键入时立即显示结果 . 听起来很熟悉,但这项任务带来了很多挑战 .

    • 我们不希望每次用户按下某个键时都会点击服务器 endpoints ,它应该充满了一堆 HTTP 请求 . 基本上,我们只想在用户停止键入而不是每次按键时都按下它 .

    • 对于后续请求,请勿使用 same query params 命中搜索 endpoints .

    • 处理无序响应 . 当我们同时在飞行中有多个请求时,我们必须考虑他们以意想不到的顺序返回的情况 . 想象一下,我们先输入 computer ,停止,请求输出,我们输入 car ,停止,请求输出 . 现在我们有两个飞行请求 . 不幸的是,带有 computer 结果的请求在带有 car 结果的请求之后返回 .

    该演示将只包含两个文件: app.tswikipedia-service.ts . 在现实世界中,我们很可能会将事情进一步分解 .


    下面是 Promise-based 实现,它不处理任何描述的边缘情况 .

    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<Response>Promise<Response> . 最终以 Promise<Array<string>> 作为我们搜索方法的返回类型 .

    app.ts

    // check the plnkr for the full list of imports
    import {...} from '...';
    
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>Wikipedia Search</h2>
          <input #term type="text" (keyup)="search(term.value)">
          <ul>
            <li *ngFor="let item of items">{{item}}</li>
          </ul>
        </div>
      `
    })
    export class AppComponent {
      items: Array<string>;
    
      constructor(private wikipediaService: WikipediaService) {}
    
      search(term) {
        this.wikipediaService.search(term)
                             .then(items => this.items = items);
      }
    }
    

    这里也没什么惊喜 . 我们注入 WikipediaService 并通过搜索方法将其功能暴露给模板 . 模板只是绑定到 keyup 并调用 search(term.value) .

    我们打开了_百度化服务的搜索方法返回的 Promise 的结果,并将其作为一个简单的字符串数组公开给模板,这样我们就可以循环遍历它并为我们 Build 一个列表 .

    请参阅Plunker上的 Promise-based 实施示例


    哪里 Observables 真的很闪耀

    让我们改变我们的代码,不要在每次按键时敲击 endpoints ,而只是在用户停止输入_117763_时才发送请求

    为了揭示这样的超级大国,我们首先需要获得一个带有用户输入的搜索词的 Observable<string> . 我们可以利用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” .

    <input type="text" [formControl]="term"/>
    

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

    在幕后, term 自动公开 Observable<string> 作为我们可以订阅的属性 valueChanges . 现在我们有 Observable<string> ,克服用户输入就像在 Observable 上调用 debounceTime(400) 一样简单 . 这将返回一个新的 Observable<string> ,只有在没有400ms的新值时才会发出新值 .

    export class App {
      items: Array<string>;
      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 运算符

    请参阅PlunkerObservable 实现的示例

    要处理无序响应,请查看完整文章http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

    至于我在Angular中使用Http,我同意在正常使用情况下使用Observable而不是Promise没有太大区别 . 在实践中,这些优点都没有真正相关 . 希望将来可以看到一些高级用例:)


    了解更多信息https://angular-2-training-book.rangle.io/handout/observables/ https://angular.io/tutorial/toh-pt6#observables

  • 1

    以下是承诺和观察中的一些重要差异 .

    Promise

    • 仅发出单个值

    • 不可取消

    • 不可共享

    • 始终异步

    Observable

    • 发出多个值

    • 仅在被调用或有人订阅时执行

    • 可以取消

    • 可以由多个订阅者共享和订阅该共享值 . 所有订阅者都将在一个时间点执行 .

    • 可能是异步的

    为了更好地理解,请参阅https://stackblitz.com/edit/observable-vs-promises

  • -4

    虽然接受的答案一般都很好,但我认为它并不强调在处理Angular组件时,你几乎总是想要使用Observable,因为它支持取消 . Promise无法取消,即使您的组件被销毁也会解决 . 角度往往是宽容的,直到它不是 .

    例如,对已销毁组件的任何手动更改检测都将导致异常:

    ngOnInit() {
      // promise api
      this.service.getData().then(d => {
         this.data = d;
         this.changeDetectorRef.detectChanges();
      });
    
      // observable api
      this.service.getData().pipe(takeUntil(this.unsubscribe)).subscribe((d) => {
         this.data = d;
         this.changeDetectorRef.detectChanges();
      });
    }
    

    如果在解析promise之前销毁了组件,则在解析promise时会出现 attempt to use destroyed view 错误 .

    或者,如果您使用带有takeUntil模式的observable,则只要您的组件被销毁,订阅就会被取消 .

    这是一个人为的例子,但是为被破坏的组件执行代码可能会导致错误 . 除非你因某种原因真的想这样做:p

  • 1069

    承诺 - 提供单一的未来 Value . 不懒惰 . 不可取消 . 它会拒绝或解决 .

    可观察 - 提供多种未来 Value . 懒惰 . 可以取消 . 它提供其他方法实时 Map ,过滤,减少 .

  • -8

    Promises

    • 定义:帮助您异步运行函数,并在执行时使用它们的返回值(或异常)但 only once .

    • 不懒惰

    • 不可取消 . 两个可能的决定是

    • 拒绝

    • 解决

    • 不能 retried (Promise应该可以访问返回promise的原始函数,以便具有重试功能,这是一种不好的做法)

    Observables

    • 定义:帮助您异步运行函数,并在执行时以连续序列( multiple times )使用它们的返回值 .

    • 默认情况下,它是Lazy,因为它会随着时间的推移发出值 .

    • 有很多操作符可以简化编码工作 .

    • 一个运算符 retry 可用于在需要时重试,如果我们需要根据某些条件重试observable retryWhen 可以使用 .

    Note :运营商列表及其交互式图表可在RxMarbles.com获取 .

  • 2

    Promise

    当异步操作完成或失败时, Promise 处理 single event .

    注意:那里有 Promise 库支持取消,但ES6 Promise 到目前为止还没有 .

    Observable

    Observable 类似于 Stream (在许多语言中)并允许传递零个或多个事件,其中为每个事件调用回调 .

    通常 Observable 优于 Promise ,因为它提供 Promise 等功能 . 使用 Observable ,如果要处理0,1或多个事件并不重要 . 您可以在每种情况下使用相同的API .

    Observable 也优于 Promise cancelable . 如果不再需要对服务器的HTTP请求或其他一些昂贵的异步操作的结果, ObservableSubscription 允许取消订阅,而 Promise 最终会调用成功或失败的回调,即使您没有需要通知或它提供的结果 .

    Observable提供 operators ,如 mapforEachreduce ,...类似于数组

    还有强大的运算符,如 retry() ,或 replay() ,......通常非常方便 .

  • 49

    PromisesObservables 都将帮助我们使用JavaScript中的 asynchronous functionalities . 它们在许多情况下非常相似,但是,两者之间仍然存在一些差异,承诺是将以 http 方式解决的值,例如 http 调用 . 另一方面,observables处理 asynchronous events 的序列 . 主要差异如下:

    promise:

    • 有一个管道

    • 通常只用于异步数据返回

    • 不容易取消

    observable:

    • 是可取消的

    • 本质上是可以重试的,例如重试和重试

    • 在多个管道中流数据

    • 具有类似于数组的操作,如map,filter等等
      可以从事件等其他来源创建

    • 它们是函数,可以在以后订阅

    另外,我在下面为您创建了图形图像,以便直观地显示差异:

  • 13

    Observables vs Promises

    PromisesObservables ,它们都为我们提供了一种简单的方法来帮助我们尝试尝试异步应用程序的本质 . 但是,两者之间存在重要差异:

    • Observables 可以定义异步行为的设置和拆卸方面 .

    • Observables 可取消 .

    • 此外,可以使用API提供的其中一个重试运算符重试 Observables ,例如重试和重试 . 另一方面,Promises要求调用者可以访问返回promise的原始函数,以便具有重试功能 .

    Promise实际上强制执行这种语义 . 您可以创建一个Promise,它可以解析一些值:

    const numberPromise = new Promise((resolve) => {
        resolve(5);
    });
    
    numberPromise.then(value => console.log(value));
    // will simply print 5
    

    但尝试用另一个值再次解决Promise将失败 . 始终使用传递给resolve函数的第一个值来解析Promise,并忽略对它的进一步调用:

    const numberPromise = new Promise((resolve) => {
        resolve(5);
        resolve(10);
    });
    
    numberPromise.then(value => console.log(value));
    // still prints only 5
    

    相反,Observables允许您解决(或者,如我们所说,“发出”)多个值 . 它的外观如下:

    const numberObservable = new Observable((observer) => {
        observer.next(5);
        observer.next(10);
    });
    
    numberObservable.subscribe(value => console.log(value));
    // prints 5 and 10
    

    注意语法有多相似 - 我们将Promise切换为Observable,用observer.next调用替换resolve函数,而不是使用subscribe,其行为非常相似 .

  • 236

    Short answer :

    Observablebetter ,它具有所有 Promises 功能和额外功能 .


    Long answer:

    Promises:

    • 一次性使用"Return data once"

    • 没有取消

    • 一个听众

    • 没有套接字支持一个监听器

    Observable:

    • 数据更改时多次返回数据

    • 支持取消

    • 支持套接字

    • 支持多个侦听器,并在数据更改时通知它们

    • 支持 Map ,过滤,减少

  • 15

    Observables和Promise正在帮助我们使用JavaScript / typescript中的异步功能 . 它们在许多情况下非常相似,但它们之间仍然存在一些差异 .

  • 23

    在答案中缺少Observables的一个缺点 . Prom允许使用ES7异步/等待函数 . 使用它们,您可以编写异步代码,就像它是同步函数调用一样,因此您不再需要回调 . Observables执行此操作的唯一可能性是将它们转换为Promises . 但是当你将它们转换为Promises时,你只能再次获得一个返回值:

    async function getData(){
        const data = await observable.first().toPromise();
        //do stuff with 'data' (no callback function needed)
    }
    

    进一步阅读:How can I await on an Rx Observable?

  • 149

    Observables和Promises都提供了一种在JavaScript中处理 async 活动的方法 . 虽然Promise要么 reject/resolve 基于单个异步事件(http请求)的完成,Observables可以根据订阅它们的观察者不断发出状态变化 .

    它们之间的一个基本区别是,observable提供了一个请求和一个新请求的方法 . 承诺不允许这样的功能 .

    此外,Promise会发出单个值,而Observable会发出多个值 . 因此,在处理HTTP请求时,Promise可以为同一个请求管理单个响应,但是如果对同一个请求有多个响应,那么我们必须使用Observable .

  • 4

    我刚刚处理了一个问题,其中Promises是最好的解决方案,我在这里分享它,因为任何人在这个问题很有用的情况下绊倒了这个问题(这正是我之前寻找的答案):

    在Angular2项目中,我有一个服务,它接受一些参数并返回一个值列表来填充表单上的下拉菜单 . 当表单组件初始化时,我需要使用不同的参数多次调用相同的服务来定义许多不同的下拉菜单,但是如果我只是将所有变量排队以调用服务,则只有最后一个成功并且其余错误出 . 从数据库获取的服务一次只能处理一个请求 .

    成功填充所有下拉菜单变量的唯一方法是以阻止在上一个请求完成之前处理新请求的方式调用服务,并且Promise / .then机制很好地解决了问题 .

    fetchValueList(listCode): Promise<any> {
          return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
              .map(response => response.json())
              .toPromise();
      }
    
      initializeDropDowns() {
          this.fetchValueList('First-Val-List')
              .then(data => {
                  this.firstValList = data;
                  return this.fetchValueList('Second-Val-List')
              }).then(data => {
                  this.secondValList = data;
                  return this.fetchValueList('Third-Val-List')
              }).then(data => {
                  this.thirdValList = data;
              })  }
    

    我在组件中定义了函数,然后在ngOnInit中调用了initializeDropDowns() .

    fetchValueList函数返回一个Promise,因此第一个调用传递第一个listCode,当Promise解析时,返回值位于.then块的数据变量中,我们可以将它分配给this.firstValList变量 . 当函数返回数据时,我们知道服务已经完成,用第二个listCode再次调用是安全的,返回值在下一个.then块的数据变量中,我们将它分配给this.secondValList变量 .

    我们可以根据需要多次链接以填充所有变量,在最后一个代码块中我们只是省略了返回语句和块终止 .

    这是一个非常具体的用例,我们有一个单独的服务,需要在组件初始化时多次调用,服务必须完成其获取并返回一个值才能再次调用,但在这种情况下, Promise / .then方法很理想 .

  • 34

    概述:

    • Promises和Observable都帮助我们处理异步操作 . 这些异步操作完成后,它们可以调用某些回调 .

    • Promise只能处理一个事件,Observables用于随时间推移的事件流

    • 承诺一旦待决,便无法取消

    • Data Observables emit可以使用运算符进行转换

    您总是可以使用observable来处理异步行为,因为observable具有promise提供的所有功能(额外) . 但是,有时候不需要Observables提供的额外功能 . 然后为它导入一个库以便使用它们将是额外的开销 .

    何时使用Promises:

    当您具有要处理结果的 single 异步操作时,请使用promises . 例如:

    var promise = new Promise((resolve, reject) => {
      // do something once, possibly async
      // code inside the Promise constructor callback is getting executed synchronously
    
      if (/* everything turned out fine */) {
        resolve("Stuff worked!");
      }
      else {
        reject(Error("It broke"));
      }
    });
    
    //after the promise is resolved or rejected we can call .then or .catch method on it
    
    promise.then((val) => console.log(val))      // logs the resolve argument
           .catch((val) => console.log(val));    // logs the reject argument
    

    所以一个promise会执行一些解析或拒绝的代码 . 如果调用resolve或reject,则promise从 pending state 变为 resolvedrejected 状态 . 当解析promise状态时,将调用 then() 方法 . 当promise状态被拒绝时,将调用 catch() 方法 .

    何时使用Observables:

    当需要处理 stream (of data) over time 时使用Observable . 流是一系列可用的数据元素 over time . 流的示例是:

    • 用户事件,例如单击或键盘事件 . 用户随时间生成事件(数据) .

    • Websockets,在客户端与服务器 Build websocket连接之后,它随时间推送数据 .

    在Observable本身是在 next event 发生时, error occurs 时,或Observable是 completed 时指定的 . 然后我们可以订阅这个observable,它会激活它,在这个订阅中我们可以传入3个回调(并不总是传递所有) . 一个回调要为成功执行,一个回调用于错误,一个回调用于完成 . 例如:

    const observable = Rx.Observable.create(observer => {
      // create a single value and complete
      observer.onNext(1);
      observer.onCompleted();
    });
    
    source.subscribe(
      x => console.log('onNext: %s', x),   //  success callback
      e => console.log('onError: %s', e),  //  error callback
      () => console.log('onCompleted')     //  completion callback
     );
    
    // first we log: onNext: 1
    //  then we log: onCompleted
    

    在创建一个observable时,它需要一个回调函数,它将一个观察者作为一个参数 . 在这个观察者你可以调用 onNextonCompletedonError . 然后,当Observable订阅它时,它将调用传递给订阅的相应回调 .

  • 13

    Explain in reference of Angular Http calls for remote Api: Promises用于维护异步调用的状态 . one the data is obtained from remote Api and show into view

    并且 Observable 来自可观察的模式,当它为您提供设施时由Rxjs引入 to update data multiple times throughout the stream as observable data.

  • 2

    承诺:

    • 提供单一的未来 Value ;

    • 不懒惰;

    • 不可取消;

    可观察:

    • 随着时间的推移发出多个值;

    • 懒惰;

    • 可取消;

    • 支持map,filter,reduce和类似的运算符

    如果您愿意,可以在Angular中调用HTTP时使用promises而不是observable .

  • 7

    promises和Observable都只处理异步调用 . 找到上面的图像主要区别 .

  • 11

    即使这个答案迟了,我总结了下面的差异,

    Observable:

    • Observable只是 function ,需要 an observer 并返回 function Observer: an object with next, error.

    • Observer允许 subscribe/unsubscribe 到其数据流,向观察者发出下一个值, notify 观察者关于 errors 并通知观察者 stream completion

    • Observer提供 function to handle next value ,错误和流结束(ui事件,http响应,带Web套接字的数据) .

    • 随着时间的推移与 multiple values 一起使用

    • 它是 cancel-able/retry-able 并支持 map,filter,reduce 等运营商 .

    • 创建Observable可以-- Observable.create() - 返回可以调用方法的Observable - Observer Observable.from() - 将数组或者iterable转换为 - Observable Observable.fromEvent() - 将事件转换为Observable - Observable.fromPromise() - 将Promise转换为Observable - Observable.range() - 返回一个整数序列具体的范围

    Promise

    • 承诺代表着将来完成的任务;

    • 承诺成为 resolved by a value ;

    • 承诺被例外拒绝;

    • cancellable 并返回 a single value

    • 承诺公开函数 (then)

    然后返回一个新的 promise ;

    • 允许 attachment 将根据 state 执行;

    • handlersguaranteedorder attached 中执行;

  • 5

    关于这个主题已经有很多答案,所以我不会添加冗余的答案 .

    但对于刚刚开始学习 Observable / Angular 并想知道使用哪一个与 Promise 比较的人,我建议您保留所有Observable并将项目中的所有现有Promise转换为Observable .

    仅仅因为Angular框架本身及其社区全部使用Observable . 因此,当您集成框架服务或第三方模块并将所有内容链接在一起时,这将是有益的 .


    虽然我欣赏所有的downvotes,但我仍然坚持我的观点,除非有人发表适当的评论列出一些可能在你的Angular项目中使用Promises over Observables仍然有用的场景 .

    当然,没有任何意见在所有情况下100%正确,但至少我认为98%的时间是在Angular框架中实施的常规商业项目,Observable是正确的方法 .

    即使你在简单的爱好项目的起点不喜欢它,你很快就会意识到你在Angular中几乎所有与之交互的组件,并且大多数Angular友好的第三方框架都使用了Observables,然后你就会最终不断将你的Promise转换为Observable以便与他们沟通 .

    这些组件包括但不限于:HttpClient,表单构建器,角度材料模块/对话框,Ngrx存储/效果和ngx-bootstrap .

    事实上,我在过去两年中处理过的Angular生态系统的唯一承诺是 APP_INITIALIZER .

相关问题