Platform: Performance Issues with Dev Tools + Router-Store

Created on 19 Jul 2017  路  12Comments  路  Source: ngrx/platform

I've found that my app becomes quite slow if StoreRouterConnectingModule and StoreDevtoolsModule are both imported.

StoreModule.forRoot(reducers),
...(!environment.production ? [StoreDevtoolsModule.instrument({ maxAge: 10 })] : []),
EffectsModule.forRoot([]),
StoreRouterConnectingModule,

Observations

  • CPU usage by Chrome is at least 30% constantly. In the Chrome task manager I've seen the dev tools extension process use 100%+ CPU and 2+ GB of RAM.
  • I started with maxAge: 50, changing it to as low as maxAge: 2 didn't help.
  • Performance seemed to be worse if I flipped the order of EffectsModule and StoreRouterConnectingModule.
  • I found that exporting the state from the dev tools yielded a 27 MB JSON file. If the StoreRouterConnectingModule was removed, it was 71 KB.
  • Most of the 27 MB file has data like this:
 "computedStates": [
    {
      "state": {
        "router": {
          "state": {
            "_root": {
              "value": {
                "url": [],
                "params": {},
                "queryParams": {},
                "data": {},
                "outlet": "primary",
                "_routeConfig": null,
                "_urlSegment": {
                  "segments": [],
                  "children": {
                    "primary": {
                      "segments": [
                        {
                          "path": "app",
                          "parameters": {}
                        },
                        {
                          "path": "users",
                          "parameters": {}
                        }
                      ],
                      "children": {},
                      "parent": {
                        "segments": {
                          "$jsan": "$.computedStates[0].state.router.state._root.value._urlSegment.segments"
                        },
                        "children": {
                          "$jsan": "$.computedStates[0].state.router.state._root.value._urlSegment.children"
                        },
                        "parent": null,
                        "_sourceSegment": {
                          "$jsan": "$.computedStates[0].state.router.state._root.value._urlSegment"
                        },
                        "_segmentIndexShift": 0
                      }
                    }
                  },
                  "parent": null
                },
                "_lastPathIndex": -1,
                "_resolve": {},
                "_routerState": {
                  "$jsan": "$.computedStates[0].state.router.state"
                }
              },

Profiling Results

Top of call tree:

screen shot 2017-07-18 at 13 16 38

Next highest in tree:

screen shot 2017-07-18 at 13 19 17

Versions

Angular: 4.2.6
Angular CLI: 1.2.1
NGRX: 4.0.0

Browser: Chrome 59.0.3071.115
OS: macOS 10.12.5
Node: 6.11.0
Yarn: 0.27.5

Router Store Store Devtools bug

Most helpful comment

Do we have an ETA for this issue?

All 12 comments

This is because the router state stores the RouterStateSnapshot object.

That object is huge, holding components, router tress and more goodies.

Redux dev tools tries to render it (json) deep which is a huge task.

It probably holds circular references which I don't know if the dev tools handles or not, but anyway its a heavy task.

+1, I had to disable Redux DevTools extension to be able to work on app...

+1 Likewise, unusable with router-store. Once i removed the router from state, its fine.

so I just the ngrx-store-logger. there is a big performance problem to integrate with Redux DevTools

Same here, on first init with redux dev tools opened the app crashes. Afterwards it is noticeable slower with devtools activated.

I've had similar probably with large objects in Redux Devtools previously. A way we can get around it is to wrap router states so they implement toJSON, and then manually trim down that object.

As long as we implement this on the router store object specifically (without messing with the snapshots), this shouldn't have any downstream consequences.

E.g. in router_store_module.ts, change:

return {
  state: action.payload.routerState,
  navigationId: action.payload.event.id,
};

to

return new StoreRouterState(
  action.payload.routerState,
  action.payload.event.id,
);

and then implementing StoreRouterState something like:

class RouterState {
  constructor(public state: RouterStateSnapshot, public id: number) {}
  toJSON() {
     // Truncate router object however
     return {state: {url: 'foo'}, id: this.id};
  }
}

Whether this is actually a good idea is another matter entirely. A better solution might be to allow a deserializer map to be passed to store devtools. @brandonroberts any insight here? Can this be accomplished with StoreDevtoolsConfig.monitor?

Any news on @bfricka suggestions? I think that might work.

@bfricka I talked with @vsavkin about this issue and we're going to implement a serializer for the RouterState that you can override. The RouterState is a large complex structure, but generally you may only need a small piece of it. By default, you'll get the entire RouterState, but there will be an interface you can implement to pair it down to only what you need.

This will make it easier to work with the Devtools, as if you only need the URL, the payload will be significantly smaller.

Do we have an ETA for this issue?

This also makes it impossible to serialize the state via JSON.stringify since there are circular references: ERROR TypeError: Converting circular structure to JSON

Anyone looking for an ETA on this issue, feel free to take a look at the following documentation. It offers a solution using a Custom Router State Serializer.

Update 9/21/2019: for RxJs and up can go to (https://ngrx.io/guide/router-store/configuration#custom-router-state-serializer)

News guys ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mappedinn picture mappedinn  路  3Comments

brandonroberts picture brandonroberts  路  3Comments

hccampos picture hccampos  路  3Comments

alvipeo picture alvipeo  路  3Comments

shyamal890 picture shyamal890  路  3Comments