-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
lib: avoid using Array.prototype.forEach #11582
Conversation
How many forEach's are left? Is it worth having a lint rule to catch? |
We are aware of this, and work on the Array builtins (forEach, filter, and friends) already started. |
@richardlau ... only a handful but they are either a bit more complicated to refactor or are otherwise not in code that is that performance critical. At this point I don't believe a lint rule is required. @bmeurer ... yeah, I figured as much :-) It's a significant enough of a gap right now that making this change makes sense. I've separated each changed file into a separate commit so that we can selectively roll back as necessary once performance improvements are made :-) |
I am guessing https://bugs.chromium.org/p/v8/issues/detail?id=5269 is the related tracking issue? Just linking stuff :). EDIT: or maybe this: https://bugs.chromium.org/p/v8/issues/detail?id=1956 |
benchmark/es/foreach-bench.js
Outdated
const common = require('../common.js'); | ||
|
||
const bench = common.createBenchmark(main, { | ||
method: ['array', 'forEach'], |
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 just 'for' would be more descriptive since they are both iterating over an array.
9f7a58c
to
32a726a
Compare
@mscdex ... I renamed the |
Relevant upstream bugs are https://bugs.chromium.org/p/v8/issues/detail?id=1956 and https://bugs.chromium.org/p/v8/issues/detail?id=2229. Full parity with for-of/for vs. forEach requires shipping TurboFan for all JS first, so probably V8 5.9 or 6.0 can provide the performance. |
Some forEach not in critical path. |
I've always been in favor of replacing all instances of |
Ping @nodejs/collaborators |
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.
LGTM
proxiedMethods.forEach(function(name) { | ||
tls_wrap.TLSWrap.prototype[name] = function methodProxy(...args) { | ||
function makeMethodProxy(name) { | ||
return function methodProxy(...args) { |
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'm curious why ...args
is being used when we're just using it with .apply()
which should handle arguments
just fine.
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.
Either way works for me really
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 would vote for changing to using arguments
while we're in here.
['GLOBAL', 'root'].forEach(function(name) { | ||
// getter | ||
const get = util.deprecate(function() { | ||
function makeGetter(name) { |
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.
Perhaps these could be named a bit clearer, like makeDeprecateGetter()
or maybe makeDepGetter()
, and similarly with makeSetter()
.
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.
LGTM. Tiniest nit: would you mind using i
as the loop variable instead of n
. We aren't consistent, but i
seems to be used more.
benchmark/es/foreach-bench.js
Outdated
for (i = 0; i < n; i++) { | ||
for (j in items) { | ||
/* eslint-disable no-unused-vars */ | ||
item = items[i]; |
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 doesn't use j
at all. Wouldn't this be optimized away?
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.
whoops, this is just a typo
lib/fs.js
Outdated
enumerable: true, value: constants[key] || 0, writable: false | ||
}); | ||
Object.defineProperties(fs, { | ||
F_OK: {enumerable: true, writable: false, value: constants.F_OK || 0}, |
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 drop writable
? By default it is false
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.
Ok
Hope none of the changes here involve sparse arrays. That would change the semantics of the loop iteration. |
None of the loops appear to involve sparse arrays that I can see. |
@thefourtheye ... updated to address your feedback. PTAL |
ping @thefourtheye |
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.
Sorry for the delay. Belated LGTM.
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs#11582 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@jasnell this PR need backport to v7 |
+1 for v6.x backport |
Using
Array.prototype.forEach()
is still significantly slower than traditional array iteration. This PR adds a benchmark and replaces many (but not all)forEach()
uses within lib.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
lib