-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(Angular.js): fix isArrayLike for extends #4855
Conversation
What is the performance impact of doing all the calculations up front rather than short-circuiting quick cases? |
+1 for the unit test. |
@petebacondarwin None of the cases involved require traversal. The return and boolean statements are set up to short-circuit with ORs as much as possible. If you'd like me to create a performance spec I can do that. Interestingly, IE8 on win 7 is returning a bunch of
errors in the Travis Build. I can download an IE8 vm and investigate, but if you know if the build was failing before this pr, that would be immensely helpful. I didn't get any errors using |
You call all these functions before you begin to short-circuit:
Plus these may also get called:
|
BTW IE8 doesn't always have |
No problem, I can polyfill.
|
Haven't worked in it in over two years.
|
http://jsperf.com/angular-isarraylike-performance The current implementation is faster. But it doesn't identify arguments objects correctly. Want me to plug an early return into that setup as well? |
Added the early exit impl test. I am seeing that the new impl is 59% slower than the current broken implementation, and the early exit version of the new impl is 44% slower than the current broken implementation. I don't know that the project preferences are, but the removal of the if-return boolean doesn't seem necessary for a 15% increase in correct performance. I am adding the |
) || | ||
isSomeOtherObj | ||
) | ||
); |
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 feel like these long expressions are actually much harder to mentally parse/understand, and you also lose the locality of reference benefit (everything is evaluated at the head, but used a full page down). And these may be a big part of the performance degrading.
@caitp @petebacondarwin I have added a I have also reworded the specifications and specification local variable names to make them clearer to understand. |
@jackcviers: You can use |
@caitp Yeah, I'm testing to see if |
http://jsfiddle.net/tUNnY/ — Try it in IE10, Chrome, Safari, Firefox, etc.
Caitlin Potter On Nov 10, 2013, at 9:49 PM, Jack Viers notifications@github.com wrote:
|
@caitp Yeah, that still fails on Travis. Need to get a local hook into Karma for these tests for IE vms so that I can see what is going on. I have tried exporting IE_BIN. Local when I try with |
@jackcviers you need the npm install karma-ie-launcher |
My variation on your patch is passing CI: https://travis-ci.org/caitp/angular.js/builds/13790008 --- Feel free to review it. It requires a change to |
I think that's fine, @caitp. I will pull your change over tomorrow. Thanks
|
Add spec for isArrayLike Add Arguments detection Convert NodeList detection to use hasChildren Prepares a single boolean return instead of several if return boolean statements 1. Convert if-return boolean statements to single boolean return. 2. Assign boolean conditionals to break up the long boolean return and avoid repeated calls. 3. Declare variables at the beginning of function to avoid hoisting errors. Break long lines into indented and aligned expressions.
@caitp @petebacondarwin This now passes on Travis. @caitp thanks for your help. The version you gave me didn't pass on my local for some reason. This one does. Please let me know if you have any questions. |
@jackcviers any chance we could get this patch cleaned up a bit? I was a bit surprised to learn this morning that it hasn't been merged yet. Lets make it merge-able! |
Sure, I am on it.
|
Actually in hindsight, this probably isn't what I was surprised to learn today, it seems that we are calling But just the same, if this does offer some improvements, it would be nice to squish this patch down as small as possible and try to get some decent performance out of it. |
02dc2aa
to
fd2d6c0
Compare
cad9560
to
f294244
Compare
e8dc429
to
e83fab9
Compare
4dd5a20
to
998c61c
Compare
Closes angular#10186 Closes angular#8000 Closes angular#4855 Closes angular#4751 Closes angular#10272
Closes angular#10186 Closes angular#8000 Closes angular#4855 Closes angular#4751 Closes angular#10272
Closes angular#10186 Closes angular#8000 Closes angular#4855 Closes angular#4751 Closes angular#10272
Closes angular#10186 Closes angular#8000 Closes angular#4855 Closes angular#4751 Closes angular#10272
<a name="1.4.9"></a> # 1.4.9 implicit-superannuation (2016-01-21) ## Bug Fixes - **Animation** - ensure that animate promises resolve when the document is hidden ([9a60408c](angular/angular.js@9a60408)) - do not trigger animations if the document is hidden ([09f6061a](angular/angular.js@09f6061), [elastic#12842](angular/angular.js#12842), [elastic#13776](angular/angular.js#13776)) - only copy over the animation options once ([2fc954d3](angular/angular.js@2fc954d), [elastic#13722](angular/angular.js#13722), [elastic#13578](angular/angular.js#13578)) - allow event listeners on document in IE ([5ba4419e](angular/angular.js@5ba4419), [elastic#13548](angular/angular.js#13548), [elastic#13696](angular/angular.js#13696)) - allow removing classes that are added by a running animation ([6c4581fc](angular/angular.js@6c4581f), [elastic#13339](angular/angular.js#13339), [elastic#13380](angular/angular.js#13380), [elastic#13414](angular/angular.js#13414), [elastic#13472](angular/angular.js#13472), [elastic#13678](angular/angular.js#13678)) - do not use `event.timeStamp` anymore for time tracking ([620a20d1](angular/angular.js@620a20d), [elastic#13494](angular/angular.js#13494), [elastic#13495](angular/angular.js#13495)) - ignore children without animation data when closing them ([be01cebf](angular/angular.js@be01ceb), [elastic#11992](angular/angular.js#11992), [elastic#13424](angular/angular.js#13424)) - do not alter the provided options data ([7a81e6fe](angular/angular.js@7a81e6f), [elastic#13040](angular/angular.js#13040), [elastic#13175](angular/angular.js#13175)) - correctly handle `$animate.pin()` host elements ([a985adfd](angular/angular.js@a985adf), [elastic#13783](angular/angular.js#13783)) - allow animations when pinned element is parent element ([4cb8ac61](angular/angular.js@4cb8ac6), [elastic#13466](angular/angular.js#13466)) - allow enabled children to animate on disabled parents ([6d85f24e](angular/angular.js@6d85f24), [elastic#13179](angular/angular.js#13179), [elastic#13695](angular/angular.js#13695)) - correctly access `minErr` ([0c1b54f0](angular/angular.js@0c1b54f)) - ensure animate runner is the same with and without animations ([937942f5](angular/angular.js@937942f), [elastic#13205](angular/angular.js#13205), [elastic#13347](angular/angular.js#13347)) - remove animation end event listeners on close ([d9157849](angular/angular.js@d915784), [elastic#13672](angular/angular.js#13672)) - consider options.delay value for closing timeout ([592bf516](angular/angular.js@592bf51), [elastic#13355](angular/angular.js#13355), [elastic#13363](angular/angular.js#13363)) - **$controller:** allow identifiers containing `$` ([2563ff7b](angular/angular.js@2563ff7), [elastic#13736](angular/angular.js#13736)) - **$http:** throw if url passed is not a string ([c5bf9dae](angular/angular.js@c5bf9da), [elastic#12925](angular/angular.js#12925), [elastic#13444](angular/angular.js#13444)) - **$parse:** handle interceptors with `undefined` expressions ([7bb2414b](angular/angular.js@7bb2414)) - **$resource:** don't allow using promises as `timeout` and log a warning ([47486524](angular/angular.js@4748652)) - **formatNumber:** cope with large and small number corner cases ([9c49eb13](angular/angular.js@9c49eb1), [elastic#13394](angular/angular.js#13394), [elastic#8674](angular/angular.js#8674), [elastic#12709](angular/angular.js#12709), [elastic#8705](angular/angular.js#8705), [elastic#12707](angular/angular.js#12707), [elastic#10246](angular/angular.js#10246), [elastic#10252](angular/angular.js#10252)) - **input:** - fix URL validation being too strict ([6610ae81](angular/angular.js@6610ae8), [elastic#13528](angular/angular.js#13528), [elastic#13544](angular/angular.js#13544)) - add missing chars to URL validation regex ([2995b54a](angular/angular.js@2995b54), [elastic#13379](angular/angular.js#13379), [elastic#13460](angular/angular.js#13460)) - **isArrayLike:** recognize empty instances of an Array subclass ([323f9ab7](angular/angular.js@323f9ab), [elastic#13560](angular/angular.js#13560), [elastic#13708](angular/angular.js#13708)) - **ngInclude:** do not compile template if original scope is destroyed ([9590bcf0](angular/angular.js@9590bcf)) - **ngOptions:** - don't skip `optgroup` elements with `value === ''` ([85e392f3](angular/angular.js@85e392f), [elastic#13487](angular/angular.js#13487), [elastic#13489](angular/angular.js#13489)) - don't `$dirty` multiple select after compilation ([f163c905](angular/angular.js@f163c90), [elastic#13211](angular/angular.js#13211), [elastic#13326](angular/angular.js#13326)) - **select:** re-define `ngModelCtrl.$render` in the `select` directive's postLink function ([529b2507](angular/angular.js@529b250), [elastic#13583](angular/angular.js#13583), [elastic#13583](angular/angular.js#13583), [elastic#13663](angular/angular.js#13663)) ## Minor Features - **ngLocale:** add support for standalone months ([54c4041e](angular/angular.js@54c4041), [elastic#3744](angular/angular.js#3744), [elastic#10247](angular/angular.js#10247), [elastic#12642](angular/angular.js#12642), [elastic#12844](angular/angular.js#12844)) - **ngMock:** add support for `$animate.closeAndFlush()` ([512c0811](angular/angular.js@512c081)) ## Performance Improvements - **ngAnimate:** speed up `areAnimationsAllowed` check ([2d3303dd](angular/angular.js@2d3303d)) ## Breaking Changes While we do not deem the following to be a real breaking change we are highlighting it here in the changelog to ensure that it does not surprise anyone. - **$resource:** due to [47486524](angular/angular.js@4748652), **Possible breaking change** for users who updated their code to provide a `timeout` promise for a `$resource` request in version v1.4.8. Up to v1.4.7 (included), using a promise as a timeout in `$resource`, would silently fail (i.e. have no effect). In v1.4.8, using a promise as timeout would have the (buggy) behaviour described in angular/angular.js#12657 (comment). (I.e. it will work as expected for the first time you resolve the promise and will cancel all subsequent requests after that - one has to re-create the resource class. This was not documented.) With this change, using a promise as timeout in v1.4.9 onwards is not allowed. It will log a warning and ignore the timeout value. If you need support for cancellable `$resource` actions, you should upgrade to version 1.5 or higher. <a name="1.4.8"></a> # 1.4.8 ice-manipulation (2015-11-19) ## Bug Fixes - **$animate:** ensure leave animation calls `close` callback ([6bd6dbff](angular/angular.js@6bd6dbf), [elastic#12278](angular/angular.js#12278), [elastic#12096](angular/angular.js#12096), [elastic#13054](angular/angular.js#13054)) - **$cacheFactory:** check key exists before decreasing cache size count ([2a5a52a7](angular/angular.js@2a5a52a), [elastic#12321](angular/angular.js#12321), [elastic#12329](angular/angular.js#12329)) - **$compile:** - bind all directive controllers correctly when using `bindToController` ([5d8861fb](angular/angular.js@5d8861f), [elastic#11343](angular/angular.js#11343), [elastic#11345](angular/angular.js#11345)) - evaluate against the correct scope with bindToController on new scope ([b9f7c453](angular/angular.js@b9f7c45), [elastic#13021](angular/angular.js#13021), [elastic#13025](angular/angular.js#13025)) - fix scoping of transclusion directives inside replace directive ([74da0340](angular/angular.js@74da034), [elastic#12975](angular/angular.js#12975), [elastic#12936](angular/angular.js#12936), [elastic#13244](angular/angular.js#13244)) - **$http:** apply `transformResponse` even when `data` is empty ([c6909464](angular/angular.js@c690946), [elastic#12976](angular/angular.js#12976), [elastic#12979](angular/angular.js#12979)) - **$location:** ensure `$locationChangeSuccess` fires even if URL ends with `#` ([6f8ddb6d](angular/angular.js@6f8ddb6), [elastic#12175](angular/angular.js#12175), [elastic#13251](angular/angular.js#13251)) - **$parse:** evaluate once simple expressions only once ([e4036824](angular/angular.js@e403682), [elastic#12983](angular/angular.js#12983), [elastic#13002](angular/angular.js#13002)) - **$resource:** allow XHR request to be cancelled via a timeout promise ([7170f9d9](angular/angular.js@7170f9d), [elastic#12657](angular/angular.js#12657), [elastic#12675](angular/angular.js#12675), [elastic#10890](angular/angular.js#10890), [elastic#9332](angular/angular.js#9332)) - **$rootScope:** prevent IE9 memory leak when destroying scopes ([87b0055c](angular/angular.js@87b0055), [elastic#10706](angular/angular.js#10706), [elastic#11786](angular/angular.js#11786)) - **Angular.js:** fix `isArrayLike` for unusual cases ([70edec94](angular/angular.js@70edec9), [elastic#10186](angular/angular.js#10186), [elastic#8000](angular/angular.js#8000), [elastic#4855](angular/angular.js#4855), [elastic#4751](angular/angular.js#4751), [elastic#10272](angular/angular.js#10272)) - **isArrayLike:** handle jQuery objects of length 0 ([d3da55c4](angular/angular.js@d3da55c)) - **jqLite:** - deregister special `mouseenter` / `mouseleave` events correctly ([22f66025](angular/angular.js@22f6602), [elastic#12795](angular/angular.js#12795), [elastic#12799](angular/angular.js#12799)) - ensure mouseenter works with svg elements on IE ([c1f34e8e](angular/angular.js@c1f34e8), [elastic#10259](angular/angular.js#10259), [elastic#10276](angular/angular.js#10276)) - **limitTo:** start at 0 if `begin` is negative and exceeds input length ([4fc40bc9](angular/angular.js@4fc40bc), [elastic#12775](angular/angular.js#12775), [elastic#12781](angular/angular.js#12781)) - **merge:** - ensure that jqlite->jqlite and DOM->DOM ([2f8db1bf](angular/angular.js@2f8db1b)) - clone elements instead of treating them like simple objects ([838cf4be](angular/angular.js@838cf4b), [elastic#12286](angular/angular.js#12286)) - **ngAria:** don't add tabindex to radio and checkbox inputs ([59f1f4e1](angular/angular.js@59f1f4e), [elastic#12492](angular/angular.js#12492), [elastic#13095](angular/angular.js#13095)) - **ngInput:** change URL_REGEXP to better match RFC3987 ([cb51116d](angular/angular.js@cb51116), [elastic#11341](angular/angular.js#11341), [elastic#11381](angular/angular.js#11381)) - **ngMock:** reset cache before every test ([91b7cd9b](angular/angular.js@91b7cd9), [elastic#13013](angular/angular.js#13013)) - **ngOptions:** - skip comments and empty options when looking for options ([0f58334b](angular/angular.js@0f58334), [elastic#12190](angular/angular.js#12190), [elastic#13029](angular/angular.js#13029), [elastic#13033](angular/angular.js#13033)) - override select option registration to allow compilation of empty option ([7b2ecf42](angular/angular.js@7b2ecf4), [elastic#11685](angular/angular.js#11685), [elastic#12972](angular/angular.js#12972), [elastic#12968](angular/angular.js#12968), [elastic#13012](angular/angular.js#13012)) ## Performance Improvements - **$compile:** use static jquery data method to avoid creating new instances ([55ad192e](angular/angular.js@55ad192)) - **copy:** - avoid regex in `isTypedArray` ([19fab4a1](angular/angular.js@19fab4a)) - only validate/clear if the user specifies a destination ([d1293540](angular/angular.js@d129354), [elastic#12068](angular/angular.js#12068)) - **merge:** remove unnecessary wrapping of jqLite element ([ce6a96b0](angular/angular.js@ce6a96b), [elastic#13236](angular/angular.js#13236)) ## Breaking Changes Signed-off-by: Kevin Kirsche <Kev.Kirsche@gmail.com>
Add spec for isArrayLike
Change element detection to use Node.
hasChildren
Add Arguments detection
Prepares a single boolean return instead of several if return boolean
statements
and avoid repeated calls.
Break long lines into indented and aligned expressions.
#4751