-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix($location): avoid unnecessary $locationChange*
events due to empty hash
#16636
Conversation
|
1 similar comment
|
src/ng/browser.js
Outdated
@@ -143,7 +143,7 @@ function Browser(window, document, $log, $sniffer, $$taskTrackerFactory) { | |||
// - pendingLocation is needed as browsers don't allow to read out | |||
// the new location.href if a reload happened or if there is a bug like in iOS 9 (see | |||
// https://openradar.appspot.com/22186109). | |||
return pendingLocation || location.href; | |||
return pendingLocation || trimEmptyHash(location.href); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about pendingLocation
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pendingLocation
always has the empty hash fragment stripped. In a nutshell, pendingLocation
is always the value $browser.url(url)
is called with, which is always $location.absUrl()
(directly or indirectly), which always has the empty hash stripped off.
This potential difference between pendingLocation
and location.href
is what causes the issue. Because while pendingLocation
is defined, $browser.url()
return the url without the empty hash, but once pendingLocation
gets undefined (i.e. on hashchange
, popstate
, which may be triggered asynchronously), then $browser.url()
starts returning the url with the empty fragment.
So, the returned url changes, even if there is no actual change in the url.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This potential difference between pendingLocation and location.href is what causes the issue
Aha, that helps me understand this a bit more. Why does location.href
have the hash in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what browsers do (sometimes 😁). I found that this can happen when clicking a link with a trailing # (but not when directly setting location.hash
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd vote to still do trimEmptyHash(pendingLocation || location.href)
just for consistency...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Where is |
This is one place. There may be others. Also, this looks a little problematic: Lines 970 to 979 in 6706353
Although we don't trim the empty hash for determining there's been a url change, we trim it before broadcasting the event. So, you will get a In general, I prefer to address the root of the problem. Patching stuff "just-in-time" to avoid a specific bug makes the code too complicated and hard to follow. (But I understand |
While patching stuff "just-in-time" can be iffy, modifying something generic like For the |
My point is that the proposed change does apply everywhere and does not change the behavior of But I will understand if you feel uncomfortable with changing |
But is adding/removing |
I think you already found #16636 (comment), which (kind of) explains that it's not the browser that thinks there's a change, it's |
I mean if you append I guess I just want to acknowledge that the browser does consider them different, it's only us/ I'm curious what other code could be simplified with the current fix... and how the |
src/ng/location.js
Outdated
@@ -93,7 +94,7 @@ function stripHash(url) { | |||
} | |||
|
|||
function trimEmptyHash(url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove some calls to this within this file now that $browser
does it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that is many places we trim the empty hash before using the returned url. (If we decide this fix is desired, I will remove those unnecessary calls.)
000489f
to
efb1706
Compare
src/ng/browser.js
Outdated
@@ -1,5 +1,14 @@ | |||
'use strict'; | |||
/* global stripHash: true */ | |||
/* global getHash: true, stripHash: false, trimEmptyHash: true */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is getHash
used globally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is "used" in tests, in a mock window. The feature that relies on it is not actually used atm, so there were no breakages.
See 34fe24f (yes, there is a typo in that commit message 😁).
@@ -1,4 +1,5 @@ | |||
'use strict'; | |||
/* global stripHash: true */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could move stripHash
global into browser.js
as well for consistency. Otherwise you have two way importing going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stripHash
is used more in $location
than $browser
and other similar helpers (e.g. stripBaseUrl
, stripFile
) are also in $location
. I only moved trimEmptyHash
, because it is only used in $browser
now.
Even if we had imports/exports (which we don't because everything lives inside the great AngularJS IIFE 😁), I don't see two way importing going on. $location
would export stripHash
and $browser
would import stripHash
and export getHash
and trimEmptyHash
.
(We definitely have enough URL-specific helpers that we could move them into a separate file and "import" from there 😁)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a little weird having $browser
depend on $location
. Or was that always the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know about "always", but it definitely was the case before this PR 😛
(And still is. This PR does not change anything in that regard.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of minor comments.
The helper is used in `fakeWindow.location.hash`. ATM, no test is using the `hash` getter, so there were no errors.
af2da25
to
cdd1f42
Compare
expect($browser.url()).toBe('http://new.com/#'); | ||
mockUpBrowser({initialUrl: 'http://new.com/#', baseHref: '/'}); | ||
inject(function($browser, $location, $window) { | ||
expect($browser.url()).toBe('http://new.com/'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The (non-public) docs for browser.url() say "Without any argument, this method just returns current value of location.href." Isn't this now wrong as the test shows a difference between url() and location.href?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Fix (among others).
What is the current behavior? (You can also link to an open issue here)
#16632
What is the new behavior (if this is a feature change)?
No unnecessary
$locationChange*
events due to empty hashDoes this PR introduce a breaking change?
Hopefully not 😁
Please check if the PR fulfills these requirements
Fix/Feature: Docs have been added/updated