Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(router-store): optimize selectQueryParams, selectQueryParam and selectFragment selectors #2764

Merged

Conversation

markostanimirovic
Copy link
Member

@markostanimirovic markostanimirovic commented Oct 27, 2020

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[x] Other... Please describe: Performance improvement

What is the current behavior?

selectQueryParams - returns query params from the last router state node
selectQueryParam - returns a query param from the last router state node
selectFragment - returns the fragment from the last router state node

What is the new behavior?

Optional chaining is introduced for all selectors.

selectQueryParams - returns query params from routerState.root
selectQueryParam - returns a query param from routerState.root
selectFragment - returns the fragment from routerState.root

Does this PR introduce a breaking change?

[x] Yes
[ ] No

Actually, this can be a breaking change in test files (for selectQueryParams, selectQueryParam and selectFragment selectors) if mock router state is defined in the wrong way. But when it is used with Angular router, there are no breaking changes.

@ngrxbot
Copy link
Collaborator

ngrxbot commented Oct 27, 2020

Preview docs changes for 37e4a91 at https://previews.ngrx.io/pr2764-37e4a919/

@markostanimirovic markostanimirovic changed the title perf(router-store): optimize router selectors refactor(router-store): optimize router selectors Oct 28, 2020
@markostanimirovic
Copy link
Member Author

markostanimirovic commented Oct 29, 2020

@alex-okrushko @brandonroberts @timdeschryver
I observed the same issue with build on master branch. Steps:

  1. rm -rf node_modules/
  2. yarn
  3. yarn ng build router-store

@brandonroberts
Copy link
Member

brandonroberts commented Oct 30, 2020

@alex-okrushko @brandonroberts @timdeschryver
I observed the same issue with build on master branch. Steps:

  1. rm -rf node_modules/
  2. yarn
  3. yarn ng build router-store

@markostanimirovic you have to use the --with-deps option to build router-store, as it depends on the store package being built first. There may be an issue with build-affected in CI when using --parallel

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, I see this was first a perf change but how does this optimize the router selectors?
Doesn't the Optional Chaining operator compile to the same code?

Since this is a refactor, I would also revert the changes made to the spec to be sure we didn't break something. Or perhaps create a second test case for the root with the added fragment and params?

@markostanimirovic
Copy link
Member Author

Out of curiosity, I see this was first a perf change but how does this optimize the router selectors?
Doesn't the Optional Chaining operator compile to the same code?

Since this is a refactor, I would also revert the changes made to the spec to be sure we didn't break something. Or perhaps create a second test case for the root with the added fragment and params?

@timdeschryver
Of course, optional chaining is not optimization, this is just an improvement to use new features :)

Optimized are three selectors: selectFragment, selectQueryParams and selectQueryParam to return the fragment/queryParam(s) from routerState.root instead of looping and returning fragment/queryParam(s) from the last router state tree node. I wrote this in PR description :)

About the breaking changes: this should not be a breaking change with Angular router, because fragment and query parameters are the same on root and any other child router tree node.

@markostanimirovic
Copy link
Member Author

I can add tests with RouterTestingModule to be sure that everything is working fine.

@timdeschryver
Copy link
Member

Optimized are three selectors: selectFragment, selectQueryParams and selectQueryParam to return the fragment/queryParam(s) from routerState.root instead of looping and returning fragment/queryParam(s) from the last router state tree node. I wrote this in PR description :)

My bad, I didn't read the description 😅.

But this change would also mean that the behavior is different (root vs current route), which you also pointed out.

So imho, we should either mark this as a breaking change or leave the implementation as is and create root selectors.
My opinion would be the second one, because these selectors are probably used in projects.
Thoughts?

I can add tests with RouterTestingModule to be sure that everything is working fine.

My comment about the spec was that originally it was verifying the child route, while it now validates the root route.
I was expecting the current tests to fail, but since I didn't read the PR's description I didn't know that this was intended.

@markostanimirovic
Copy link
Member Author

So imho, we should either mark this as a breaking change or leave the implementation as is and create root selectors.
My opinion would be the second one, because these selectors are probably used in projects.
Thoughts?

Sure, let's wait for the opinion of others, and when the final decision is made, I'll fix this PR :)

@alex-okrushko
Copy link
Member

So it is a breaking change, right?
For non-breaking changes the tests shouldn't change - just added.

Of course, optional chaining is not optimization, this is just an improvement to use new features :)

Optional chaining actually increases the generated code size. Unless we are reducing both sources code size AND generated code size, I wouldn't suggest to change it.

@markostanimirovic
Copy link
Member Author

@alex-okrushko

So it is a breaking change, right?
For non-breaking changes the tests shouldn't change - just added.

mockData object from router_selectors.spec.ts should represent Angular Router state. However, it is wrongly defined, because queryParams and fragment properties should be the same in root as well as in firstChilds down to the router state tree. That's why I changed it, to be the real mock of Angular Router state. I can revert the tests. Old ones will work with new mockData object too.

Anyway, I can mark this PR as breaking change and change its title to feature or performance.
Or simply close it, if we don't want selectQueryParams and selectFragment optimization. What do you think? 🙂

Optional chaining actually increases the generated code size. Unless we are reducing both sources code size AND generated code size, I wouldn't suggest to change it.

Okay, I will revert optional chaining 👍

@brandonroberts
Copy link
Member

@markostanimirovic What's left on this PR? Removal of the optional chaining?

@markostanimirovic
Copy link
Member Author

@brandonroberts

Tim commented:

So imho, we should either mark this as a breaking change or leave the implementation as is and create root selectors.
My opinion would be the second one, because these selectors are probably used in projects.
Thoughts?

And I wanted to hear other thoughts on this and update this PR accordingly 🙂

My opinion is that we don't need new selectors for selecting fragment and query params from root, because with Angular router and default serializer root.fragment is equal to root.firstChild.fragment (the same is for query params).

Btw, optional chaining is removed now 🙂

cc @timdeschryver

@markostanimirovic markostanimirovic changed the title refactor(router-store): optimize router selectors refactor(router-store): optimize selectFragment, selectQueryParams and selectQueryParam selectors Dec 29, 2020
@brandonroberts
Copy link
Member

I don't think we need new selectors either, but this shouldn't be a breaking change functionally because they are equivalent as you stated. I'd still mark it as a breaking change just so people are aware of it.

Copy link
Member

@brandonroberts brandonroberts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM. Just needs breaking changes to be added to commit message when merging

@timdeschryver
Copy link
Member

timdeschryver commented Dec 31, 2020

We should also add a note to the migration docs

@markostanimirovic markostanimirovic changed the title refactor(router-store): optimize selectFragment, selectQueryParams and selectQueryParam selectors perf(router-store): optimize selectQueryParams, selectQueryParam and selectFragment selectors Jan 4, 2021
@markostanimirovic
Copy link
Member Author

@brandonroberts @timdeschryver
I changed PR type from refactor to perf. Also, note is added to the migration guide 🙂

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding it to the migration guide

@brandonroberts brandonroberts merged commit 918f184 into ngrx:master Jan 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants