6

I have an Angular 5 site that receives data from a REST API, something like 1-4 requests to the API each page, and what happens is that the requests sometimes take a long time(and sometimes not).

Now, all the requests are being performed in one function using Observable :

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

my question is - could it be that the slow process is happening because an Observable is being used? Would Promises will be better for the performance? Or is there no difference between an Observable and a Promise in performance context?

levi
  • 1,077
  • 2
  • 11
  • 24
  • i have never seen any performance issue with angular. to be sure you can try by forcing `toPromise()` operator – Yanis-git Jan 17 '19 at 12:00
  • take a look at this may be helpful https://stackoverflow.com/a/43828666/3585496 – Must.Tek Jan 17 '19 at 12:05
  • I'm pretty sure, in this use case there shouldn't be any big difference between a Promise and an Observable (performance wise). You could use a Promise here, since you aren't taking advantage of the things an observable gives you. Take a look at the DevTools in the network tab and see if you can figure out if maybe your api endpoint are just slowing down sometimes. – Agash Thamo. Jan 17 '19 at 12:09
  • 1
    You say it's being processed slowly. What part is slow and how you know that? Is it this `res.json()`? – martin Jan 17 '19 at 12:48
  • As an addition to my comment: Without looking at only *Promise* and *Observable* and instead looking at *HttpClient.get* and *fetch* I ran some tests https://stackblitz.com/edit/typescript-salbr6 As you can see, this highly fluctuates and I honestly believe that changing 1-4 requests to use the other method doesn't change anything that we could see with our bare eyes. If the requests take longer, it's your server or the connection, but not the implementation of how you get the data (using http, in this context). – Agash Thamo. Jan 17 '19 at 13:37

4 Answers4

5

According to my tests, a Promise is more performant than an Observable.

I think Yanis-git test is a good start, but only shows part of the picture. It only calculates the starting of the Promise or Observable, but doesn't count the time for its resolution.

Here is the code I modified to take into account the resolution of the async functions as well: 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();

When I run the test in Chrome (on Mac), by visiting this page directly and opening the console: https://typescript-xhhseh.stackblitz.io/ I get these results:

promise: 279.65185546875ms
observable: 552.891845703125ms

And a very similar result in Firefox:

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

Running them repeatedly, I always come up with Observable taking more time than Promise, which makes sense especially because Promises are now native to JavaScript, whereas Observables are not, so they wouldn't seem to be as performant.

Special thanks to Yanis-git for coming up with the original test that I forked.

Uniphonic
  • 845
  • 12
  • 21
4

because you question intrigue me. i have create same testing which look like this :

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');

and result looks like this (can be different on your browser / setup but proportion should be the same :

observable: 34.060791015625ms
promise: 103.4609375ms

EDIT :

Another implementation with both async traitment inside :

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');

Result are close but race are win by observable.

observable: 160.162353515625ms
promise: 213.40625ms

live sample

if you want to check on stackblitz, please use real browser console to see timer output

Yanis-git
  • 7,737
  • 3
  • 24
  • 41
  • 6
    The promises in the snippet will resolve asynchronously - as microtasks - whereas the observables are synchronous, so the comparison made here is unsound. – cartant Jan 17 '19 at 12:16
  • 1
    [Base on this answer](https://stackoverflow.com/a/49911346/9483405) sound like you have right, i have edited my answer to wrap both call in `setTimeout`, do you think is better now ? – Yanis-git Jan 17 '19 at 12:49
  • Seems like a good test, but for some reason I get opposite answers from yours, showing that promise is the more efficient one. When I run the test in Chrome, by visiting this page directly and opening the console: https://typescript-gnuyxt.stackblitz.io/ I get these results: observable: 246.86181640625ms index.ts:29 promise: 165.449951171875ms Running them repeatedly, I always come up with Observable taking more time than Promise, which seems different from your results. – Uniphonic Feb 10 '20 at 18:42
  • I looked closer at the performance test you had and noticed that it didn't take into account the time for the resolving of the async functions, so I forked your code and made another test ( https://stackoverflow.com/a/60157433/4386681 ) to include the resolve, which shows that Promises are more performant. – Uniphonic Feb 10 '20 at 20:42
1

It's not actually fair example by the last comment. More right usage RxJS in this scheme would be in this modified example:

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

Working browser performance: https://typescript-uajatd.stackblitz.io

And we can see RxJS mostly wins the race :)

Anton Marinenko
  • 2,749
  • 1
  • 10
  • 16
0

The golden rule of performance troubleshooting is this: always measure; never jump to conclusions.

Start by reproducing a scenario where the page is running slowly. Check on the Network tab in your browser's developer console. How long does each network request take? Are the requests running in parallel, or is there a stair-step formation, where each request is not initiated until the previous one completes? Is there a long pause between requests, or does each one start immediately when the previous one finishes? Does the page appear loaded immediately when the last request is finished?

If you're unable to reproduce the problem, consider using a monitoring tool, like sentry.io, to help gather data. Analyze the data and find out what's taking so long. Is there a particular example of a record in your app that triggers this condition?

You should also look at application logs on the server side. How long is the server taking to respond to each request?

If you need to find out in detail what your rxjs code is doing, consider using this tool: https://github.com/cartant/rxjs-spy

I found this very helpful for local development.

Note that rxjs-spy introduces a large performance overhead, and is NOT suitable for production use.

RMorrisey
  • 7,637
  • 9
  • 53
  • 71