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

[v3.8.6] Use array.forEach instead of for of to optimize code size #18112

Merged
merged 12 commits into from
Jan 10, 2025

Conversation

dumganhar
Copy link
Contributor

@dumganhar dumganhar commented Jan 2, 2025

Babel compiles

class Foo {
  arr = [1, 2, 3, 4];
}
const foo = new Foo();
for (const e of foo.arr) {
  console.log(e);
}

to

var Foo = function Foo() {
  _defineProperty(this, "arr", []);
};
for (var _iterator = _createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
  var e = _step.value;
  console.log(e);
}

JSBenchMark ( Array Iteration)

Paste the following test code to https://jsbench.me/

Setup Javascript

class Foo {
  arr = [];
}

var foo = new Foo();

for (var i=0, t=4000; i<t; i++) {
    foo.arr.push(Math.round(Math.random() * t))
}

function _createForOfIteratorHelperLoose(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (t) return (t = t.call(r)).next.bind(t); if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var o = 0; return function () { return o >= r.length ? { done: !0 } : { done: !1, value: r[o++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

for of

var count = 0;
for (const e of foo.arr) {
  count += e;
}

for babel iterator

var count = 0;
for (var _iterator = _createForOfIteratorHelperLoose(foo.arr), _step; !(_step = _iterator()).done;) {
  var e = _step.value;
  count += e;
}

for index

var count = 0;
const len = foo.arr.length;
const arr = foo.arr;
for (let i = 0; i < len; ++i) {
	const e = arr[i];
  count += e;
}

forEach

var count = 0;
foo.arr.forEach((e)=> {
	count += e;
});

Result (Array Iteration)

企业微信截图_a002256a-a99f-4907-89d7-b1983eab5b30

JSBenchMark ( Object Iteration)

Setup Javascript

function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var Foo = function Foo() {
  _defineProperty(this, "obj", {});
};
var foo = new Foo();
for (var i = 0, t = 4000; i < t; i++) {
  foo.obj['hello' + i] = Math.round(Math.random() * t);
}

var count = 0;
var obj = foo.obj;

[object] for in

for (var key in obj) {
  var v = obj[key];
  count += v;
}

[object] for in and check whether own property

for (const key in obj) {
  if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
  const v = obj[key];
  count += v;
}

[object] for index and Object.keys

for (var _i = 0, _Object$keys = Object.keys(obj); _i < _Object$keys.length; _i++) {
  var key = _Object$keys[_i];
  var v = obj[key];
  count += v;
}

[object] for of

for (const key of Object.keys(obj)) {
  const v = obj[key];
  count += v;
}

Result (Object Iteration)

WeChatd829f05820b5936e4b3069b541ffee10

Re: #

Changelog


Continuous Integration

This pull request:

  • needs automatic test cases check.

    Manual trigger with @cocos-robot run test cases afterward.

  • does not change any runtime related code or build configuration

    If any reviewer thinks the CI checks are needed, please uncheck this option, then close and reopen the issue.


Compatibility Check

This pull request:

  • changes public API, and have ensured backward compatibility with deprecated features.
  • affects platform compatibility, e.g. system version, browser version, platform sdk version, platform toolchain, language version, hardware compatibility etc.
  • affects file structure of the build package or build configuration which requires user project upgrade.
  • introduces breaking changes, please list all changes, affected features and the scope of violation.

@dumganhar dumganhar marked this pull request as draft January 2, 2025 10:32
Copy link

github-actions bot commented Jan 2, 2025

👍 Package size ⤵ -1216 bytes, old: 5280335, new: 5279119

Interface Check Report

This pull request does not change any public interfaces !

@dumganhar dumganhar changed the title [TEST][v3.8.6] Test code size between for of and for index. [TEST][v3.8.6] Test code size between for of and for index, forEach. Jan 3, 2025
@dumganhar
Copy link
Contributor Author

@cocos-robot run test cases

}
this._cameras.splice(0);
});
this._cameras.length = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use this._cameras.length = 0; instead of this._cameras.splice(0); to improve a little performance.

Copy link

github-actions bot commented Jan 3, 2025

@dumganhar, Please check the result of run test cases:

Task Details

Platform build boot runned crashScene FailScene
web-mobile PASS PASS FAIL dynamic-mesh dynamic-mesh
ios PASS PASS PASS
mac PASS PASS PASS

Copy link

github-actions bot commented Jan 3, 2025

@dumganhar, Please check the result of run test cases:

Task Details

Platform build boot runned crashScene FailScene
windows PASS PASS PASS
android PASS PASS PASS
wechatgame PASS PASS FAIL dynamic-mesh dynamic-mesh

@dumganhar dumganhar requested a review from minggo January 9, 2025 02:31
@dumganhar dumganhar marked this pull request as ready for review January 9, 2025 02:31
@dumganhar dumganhar changed the title [TEST][v3.8.6] Test code size between for of and for index, forEach. [v3.8.6] Use array.forEach instead of for of to optimize code size Jan 9, 2025
this.optimizedKeys = new Array<geometry.OptimizedKey>(); // the i-th optimezed key stores coefficients of [i,i+1] segment in the original curve,so if the time of last key of the original key is 1,the last key won't be kept in the opt curve.
this.integral = new Array<number>(); // the integral of the curve between 0 and corresponding key,the i-th integral corresponds to the i+1-th key in optimizedKeys (because the integral of the first key is always zero,the first key won't be stored)
this.optimizedKeys = []; // the i-th optimezed key stores coefficients of [i,i+1] segment in the original curve,so if the time of last key of the original key is 1,the last key won't be kept in the opt curve.
this.integral = []; // the integral of the curve between 0 and corresponding key,the i-th integral corresponds to the i+1-th key in optimizedKeys (because the integral of the first key is always zero,the first key won't be stored)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

[] contains less code than new Array().

@dumganhar
Copy link
Contributor Author

@cocos-robot run test cases

Copy link

github-actions bot commented Jan 9, 2025

@dumganhar, Please check the result of run test cases:

Task Details

Platform build boot runned crashScene FailScene
web-mobile PASS PASS FAIL dynamic-mesh dynamic-mesh
ios PASS PASS PASS
mac PASS PASS PASS

Copy link

github-actions bot commented Jan 9, 2025

@dumganhar, Please check the result of run test cases:

Task Details

Platform build boot runned crashScene FailScene
windows PASS PASS PASS
android PASS PASS PASS
wechatgame PASS PASS FAIL dynamic-mesh dynamic-mesh

@dumganhar dumganhar merged commit e400883 into cocos:v3.8.6 Jan 10, 2025
12 checks passed
dumganhar added a commit to dumganhar/cocos-engine that referenced this pull request Jan 14, 2025
dumganhar added a commit that referenced this pull request Jan 14, 2025
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.

3 participants