Angular 5 - Promise vs Observable - 性能上下文

Posted

技术标签:

【中文标题】Angular 5 - Promise vs Observable - 性能上下文【英文标题】:Angular 5 - Promise vs Observable - performance context 【发布时间】:2019-06-11 14:55:48 【问题描述】:

我有一个 Angular 5 站点,它从 REST API 接收数据,例如每个页面对 API 的 1-4 个请求, 结果是请求有时需要很长时间(有时不需要)。

现在,所有请求都使用 Observable 在一个函数中执行:

return this.http.post(url, headers: this.header)
        .map(res => res.json())      
        .catch(this.handleError)

我的问题是 - 会不会是因为使用了 Observable 而导致进程缓慢? Promises 对性能会更好吗? 还是在性能上下文中 Observable 和 Promise 之间没有区别?

【问题讨论】:

我从未见过 angular 的任何性能问题。确保您可以尝试强制toPromise() operator 看看这可能会有帮助***.com/a/43828666/3585496 我很确定,在这个用例中,Promise 和 Observable 之间不应该有任何大的区别(性能方面)。你可以在这里使用 Promise,因为你没有利用 observable 给你的东西。查看网络选项卡中的 DevTools,看看您是否可以确定您的 api 端点是否有时会变慢。 你说处理速度很慢。哪一部分是慢的,你怎么知道的?这是res.json()吗? 作为我评论的补充:不只查看 PromiseObservable 而是查看 HttpClient.get并且 fetch 我运行了一些测试 stackblitz.com/edit/typescript-salbr6 正如你所看到的,这波动很大,我真诚地相信更改 1-4 个请求以使用其他方法并不会改变我们可以看到的任何内容裸露的眼睛。如果请求需要更长的时间,那是您的服务器或连接,而不是您如何获取数据的实现(在这种情况下使用 http)。 【参考方案1】:

因为你的问题引起了我的兴趣。我创建了相同的测试,如下所示:

console.time('observable');
for(let i = 0; i < 10000; i++) 
  let user$ = of(
    name: 'yanis-git'
  );

  user$.subscribe(user => 
    // do something. Prefer not console.log because is ressource consuming.
  );

console.timeEnd('observable');

console.time('promise');
for(let i = 0; i < 10000; i++) 
  new Promise((resolve) => 
    resolve(
      name: 'promise'
    );
  ).then(user => 
    // do something. Prefer not console.log because is ressource consuming.
  );

console.timeEnd('promise');

结果看起来像这样(在您的浏览器/设置上可能会有所不同,但比例应该相同:

observable: 34.060791015625ms
promise: 103.4609375ms

编辑:

另一个同时具有异步特征的实现:

console.time('observable');
for(let i = 0; i < 10000; i++) 
  let user$ = Observable.create((o) => 
    setTimeout(() => 
      o.next(
        name: 'observable'
      );
    );
  );

  user$.subscribe(user => 
    // do something. Prefer not console.log because is ressource consuming.
  );

console.timeEnd('observable');

console.time('promise');
for(let i = 0; i < 10000; i++) 
  new Promise((resolve) => 
    setTimeout(() => resolve(
      name: 'promise'
    ))
  ).then(user => 
    // do something. Prefer not console.log because is ressource consuming.
  );

console.timeEnd('promise');

结果很接近,但比赛是由 observable 赢得的。

observable: 160.162353515625ms
promise: 213.40625ms

live sample

如果要查看 stackblitz,请使用真实浏览器控制台查看计时器输出

【讨论】:

sn-p 中的 promise 将异步解析 - 作为微任务 - 而 observables 是同步的,所以这里的比较是不合理的。 Base on this answer 听起来你说得对,我已经编辑了我的答案以将两个电话都包含在setTimeout 中,你认为现在更好吗? 似乎是一个很好的测试,但出于某种原因,我从你那里得到了相反的答案,表明承诺是更有效的。当我在 Chrome 中运行测试时,通过直接访问此页面并打开控制台:typescript-gnuyxt.stackblitz.io 我得到以下结果: observable: 246.86181640625ms index.ts:29 promise: 165.449951171875ms 反复运行它们,我总是想出 Observabletaking比 Promise 更多的时间,这似乎与你的结果不同。 我仔细查看了您的性能测试,发现它没有考虑解析异步函数的时间,所以我分叉了您的代码并进行了另一个测试(***.com/a/60157433/4386681 ) 来包含解析,这表明 Promises 的性能更高。【参考方案2】:

根据我的测试,Promise 比 Observable 性能更高。

我认为Yanis-git 测试是一个好的开始,但只显示了部分图片。它只计算 Promise 或 Observable 的开始,但不计算其解析的时间。

这是我修改的代码,以考虑异步函数的分辨率: https://stackblitz.com/edit/typescript-xhhseh?file=index.ts

import  of, Observable, zip  from 'rxjs';
console.clear();

function testPromise()
  console.time('promise');
  const promiseAry = [];
  for(let i = 0; i < 10000; i++) 
    promiseAry[i] = new Promise((resolve) => 
      setTimeout(() => resolve(
        name: 'promise'
      ))
    ).then(user => 
      // do something. Prefer not console.log because is ressource consuming.
    );
  
  Promise.all(promiseAry).then(() =>
    console.timeEnd('promise');

    // test Observables after Promises have completed
    testObservable();
  )


function testObservable()
  console.time('observable');
  const observeAry = [];
  for(let i = 0; i < 10000; i++) 
    observeAry[i] = Observable.create((o) => 
      setTimeout(() => 
        o.next(
          name: 'observable'
        );
      );
    );

    observeAry[i].subscribe(user => 
      // do something. Prefer not console.log because is ressource consuming.
    );
  
  let source$ = zip(...observeAry);
  source$.subscribe(([weatherInfo, tweetInfo]) =>
    console.timeEnd('observable')
  );



testPromise();

当我在 Chrome(在 Mac 上)中运行测试时,直接访问此页面并打开控制台:https://typescript-xhhseh.stackblitz.io/ 我得到以下结果:

promise: 279.65185546875ms
observable: 552.891845703125ms

在 Firefox 中的结果非常相似:

promise: 232ms - timer ended 
observable: 319ms - timer ended

反复运行它们,我总是想出 Observable 比 Promise 花费更多的时间,这是有道理的,特别是因为 Promise 现在是 javascript 原生的,而 Observables 不是,所以它们似乎没有那么高性能。

特别感谢 Yanis-git 提出我 fork 的原始测试。

【讨论】:

【参考方案3】:

最后一条评论实际上并不是一个公平的例子。此方案中更正确的使用 RxJS 将在此修改示例中:

https://stackblitz.com/edit/typescript-uajatd

工作浏览器性能:https://typescript-uajatd.stackblitz.io

我们可以看到 RxJS 大部分都赢得了比赛 :)

【讨论】:

【参考方案4】:

性能故障排除的黄金法则是:始终衡量;永远不要妄下结论。

首先重现页面运行缓慢的场景。检查浏览器开发者控制台中的网络选项卡。每个网络请求需要多长时间?请求是否并行运行,或者是否存在阶梯式结构,每个请求在前一个请求完成之前不会启动?请求之间是否有长时间的停顿,或者每个请求在前一个请求完成后立即开始?最后一个请求完成后,页面是否会立即加载?

如果您无法重现问题,请考虑使用诸如 sentry.io 之类的监控工具来帮助收集数据。分析数据并找出需要这么长时间的原因。您的应用中是否存在触发此条件的特定记录示例?

您还应该查看服务器端的应用程序日志。服务器响应每个请求需要多长时间?

如果您需要详细了解您的 rxjs 代码在做什么,请考虑使用此工具: https://github.com/cartant/rxjs-spy

我发现这对本地开发很有帮助。

请注意,rxjs-spy 会带来很大的性能开销,并且不适合生产使用。

【讨论】:

以上是关于Angular 5 - Promise vs Observable - 性能上下文的主要内容,如果未能解决你的问题,请参考以下文章

使用 Angular 1 应用程序在 Typescript 中管理 ES6/2015 Promise

Ajax VS Promise|精选博客

angular ui-router 1.0.3 和 angular.js 1.6.4 似乎使用了错误的 Promise 类型?

ReactJS vs Angular 5 vs Vue.js - 哪个框架更好?

Angular 5.0 变更检测策略 VS React 的变更检测策略

Angular 5下载带有发布请求的excel文件