javascript オブジェクトをループさせる処理で「forEach」と「map」と「for文」と「外部ライブラリ」のパフォーマンスを計測する
- 作成日 2022.07.29
- javascript
- javascript
![javascript オブジェクトをループさせる処理で「forEach」と「map」と「for文」と「外部ライブラリ」のパフォーマンスを計測する](https://mebee.info/wp-content/uploads/2022/02/javascript-1-890x500.png)
javascriptで、「forEach」と「map」と「for文」と「外部ライブラリ」で、オブジェクトをループさせる処理を行った時のパフォーマンスを計測するサンプルコードを記述してます。
環境
- OS windows11 pro 64bit
- Apache 2.4.43
- ブラウザ chrome 103.0.5060.114
パフォーマンス計測
「performance.now」を使用して、「forEach」と「map」と「for文」と「外部ライブラリ」を使用して、オブジェクトを作成してループさせる処理を100万回実行し、パフォーマンスを計測するサンプルコードとなります。
※for-inや外部ライブラリはプロトタイプまでループするものがあるため、プロトタイプを追加して、それを除外するようにして比較してます。
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.4/underscore-umd-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"
integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
// 実行回数
const times = 1_000_000;
// 空白を埋めるだけの関数
function spacePadding(val, n = 8) {
for (; val.length < n; val += ' ');
return val;
}
// 計測結果を表示
const benchmark = (name, start, end) => {
let report = (end - start).toPrecision(3);
// 表示を見やすくするため関数名に空白を埋める
name = spacePadding(name)
console.log(`実行回数:${times}回 関数名:${name} 実行時間:${report}(ms)`);
}
const obj = {
"a": "1",
"b": "2",
"c": "3",
"d": "4",
"e": "5"
}
let obj2 = {
"f": "6"
}
// Prototypeを追加(for-inや外部ライブラリはプロトタイプまでループするものがあるため)
obj.__proto__ = obj2;
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
Object.keys(obj).forEach((key) => (`key : ${key} value : ${obj[key]}`));
}
end = performance.now();
benchmark('Object.keys(obj).forEach', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
Object.entries(obj).forEach(([key, value], index) => (`key : ${key} value : ${value}`))
}
end = performance.now();
benchmark('Object.entries(obj).forEach', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
Object.entries(obj).map(([key, value]) => (`key : ${key} value : ${value}`))
}
end = performance.now();
benchmark('Object.entries(obj).map', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
for (let key in obj) { if (obj.hasOwnProperty(key)) { (`key : ${key} value : ${obj[key]}`) } }
}
end = performance.now();
benchmark('for-in', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
for (let key of Object.keys(obj)) { (`key : ${key} value : ${obj[key]}`) }
}
end = performance.now();
benchmark('for-of Object.keys', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
for (let [key, value] of Object.entries(obj)) { (`key : ${key} value : ${obj[key]}`) }
}
end = performance.now();
benchmark('for-of Object.entries', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
$.each(obj, (key, value) => { if (obj.hasOwnProperty(key)) { (`key : ${key} value : ${value}`) } })
}
end = performance.now();
benchmark('jQuery', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
_.each(obj, (value, key) => (`key : ${key} value : ${value}`))
}
end = performance.now();
benchmark('underscore', start, end);
// 計測
start = performance.now();
for (let i = 0; i < times; ++i) {
_.forIn(obj, (value, key) => { if (obj.hasOwnProperty(key)) { (`key : ${key} value : ${value}`) } })
}
end = performance.now();
benchmark('lodash', start, end);
</script>
実行結果(chrome 103.0.5060.114)
<1回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:199(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:198(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:248(ms)
実行回数:1000000回 関数名:for-in 実行時間:414(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:175(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:237(ms)
実行回数:1000000回 関数名:jQuery 実行時間:657(ms)
実行回数:1000000回 関数名:underscore 実行時間:263(ms)
実行回数:1000000回 関数名:lodash 実行時間:553(ms)
<2回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:220(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:218(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:220(ms)
実行回数:1000000回 関数名:for-in 実行時間:419(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:172(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:233(ms)
実行回数:1000000回 関数名:jQuery 実行時間:657(ms)
実行回数:1000000回 関数名:underscore 実行時間:272(ms)
実行回数:1000000回 関数名:lodash 実行時間:549(ms)
<3回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:213(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:187(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:223(ms)
実行回数:1000000回 関数名:for-in 実行時間:423(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:174(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:246(ms)
実行回数:1000000回 関数名:jQuery 実行時間:643(ms)
実行回数:1000000回 関数名:underscore 実行時間:264(ms)
実行回数:1000000回 関数名:lodash 実行時間:561(ms)
「for-of」で「Object.keys」を使用するのが一番いいという結果になりました。
firefox102の場合は「Object.keys(obj).forEach」が良さそうです。
<1回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:165(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:742(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:787(ms)
実行回数:1000000回 関数名:for-in 実行時間:168(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:203(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:556(ms)
実行回数:1000000回 関数名:jQuery 実行時間:334(ms)
実行回数:1000000回 関数名:underscore 実行時間:538(ms)
実行回数:1000000回 関数名:lodash 実行時間:413(ms)
<2回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:160(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:740(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:775(ms)
実行回数:1000000回 関数名:for-in 実行時間:168(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:202(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:549(ms)
実行回数:1000000回 関数名:jQuery 実行時間:330(ms)
実行回数:1000000回 関数名:underscore 実行時間:526(ms)
実行回数:1000000回 関数名:lodash 実行時間:399(ms)
<3回目>
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:188(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:869(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:775(ms)
実行回数:1000000回 関数名:for-in 実行時間:172(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:205(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:551(ms)
実行回数:1000000回 関数名:jQuery 実行時間:331(ms)
実行回数:1000000回 関数名:underscore 実行時間:534(ms)
実行回数:1000000回 関数名:lodash 実行時間:396(ms)
safari15.5の場合は「Object.keys(obj).forEach」が良さそうです。
実行回数:1000000回 関数名:Object.keys(obj).forEach 実行時間:282(ms)
実行回数:1000000回 関数名:Object.entries(obj).forEach 実行時間:1.16e+3(ms)
実行回数:1000000回 関数名:Object.entries(obj).map 実行時間:1.18e+3(ms)
実行回数:1000000回 関数名:for-in 実行時間:534(ms)
実行回数:1000000回 関数名:for-of Object.keys 実行時間:927(ms)
実行回数:1000000回 関数名:for-of Object.entries 実行時間:2.25e+3(ms)
実行回数:1000000回 関数名:jQuery 実行時間:648(ms)
実行回数:1000000回 関数名:underscore 実行時間:743(ms)
実行回数:1000000回 関数名:lodash 実行時間:818(ms)
-
前の記事
Linux パーミッション設定してディレクトリを作成する 2022.07.29
-
次の記事
kotlin 階層のあるListを要素を変更してフラットな状態にする 2022.07.29
コメントを書く