この記事は、Business Bank Group Developers Advent Calendar 8日目の記事です。
こんにちは、BBGの清水です。
Lodashはリスト操作やオブジェクト操作に便利なライブラリです。
chainメソッドでeach, map, filterなどの処理を繋げて実装すると可読性も上がるためよく使用しています。
ただ、純粋なJavaScriptのメソッドの方がパフォーマンスが良いと聞いて気になったので比較してみました。
今回は、私がよく開発で使っていた処理を比較してみました。(今Angularで開発しているのでコードはtypescriptです)
事前データ
let data1: { a: number, b: number[] }[] = [];
let data2: { a: number, b: number[] }[] = [];
Array.from({ length: 10000 }, (_) => {
const num = Math.random();
data1.push({ a: num, b: [1,2,3] });
data2.push({ a: num, b: [1,2,3] });
});
Pattern 1
リスト内の特定の値をフィルタしたものをsummaryしたい
pureJS(data: { a: number, b: number[] }[]) {
let sum = 0;
const startMs = performance.now();
data.map((item) => { return item.a })
.filter((a) => a % 2)
.forEach((o) => sum += o);
return performance.now() - startMs;
}
lodash(data: { a: number, b: number[] }[]) {
const startMs = performance.now();
_.chain(data).map('a')
.filter((a) => a % 2)
.sum().value();
return performance.now() - startMs;
}
1000回呼び出した平均値で比較してみる
let result1 = [];
let result2 = [];
Array.from({ length: 1000 }, (_) => {
result1.push(this.pureJS(data1));
result2.push(this.lodash(data2));
});
console.log('PureJS(ms): ' + _.sum(result1) / 1000);
console.log('Lodash(ms): ' + _.sum(result2) / 1000);
// PureJS(ms): 0.6674000000014058
// Lodash(ms): 0.8038999999985245
Pattern 2
リストに処理を加えた後特定の値で並び替えをしたい
pureJS(data: { a: number, b: number[] }[]) {
const startMs = performance.now();
data.forEach((item) => item.a *= 3);
data.sort((l1, l2) => { return (l1.a > l2.a) ? 1 : -1 });
return performance.now() - startMs;
}
lodash(data: { a: number, b: number[] }[]) {
const startMs = performance.now();
_.chain(data).each((item) => item.a *= 3)
.sortBy('a').value();
return performance.now() - startMs;
}
1000回呼び出した平均値で比較してみる
let result1 = [];
let result2 = [];
Array.from({ length: 1000 }, (_) => {
result1.push(this.pureJS(data1));
result2.push(this.lodash(data2));
});
console.log('PureJS(ms): ' + _.sum(result1) / 1000);
console.log('Lodash(ms): ' + _.sum(result2) / 1000);
// PureJS(ms): 0.001800000000912405
// Lodash(ms): 0.014900000001944136
Pattern 3
二次元リストを一次元リストにしたい
pureJS(data: { a: number, b: number[] }[]) {
const startMs = performance.now();
data.map((o) => { return o.b })
.reduce((a, b) => a.concat(b), []);
return performance.now() - startMs;
}
lodash(data: { a: number, b: number[] }[]) {
const startMs = performance.now();
_.chain(data).map('b')
.flatten().value();
return performance.now() - startMs;
}
10回呼び出した平均値で比較してみる
let result1 = [];
let result2 = [];
Array.from({ length: 10 }, (_) => {
result1.push(this.pureJS(data1));
result2.push(this.lodash(data2));
});
console.log('PureJS(ms): ' + _.sum(result1) / 10);
console.log('Lodash(ms): ' + _.sum(result2) / 10);
// PureJS(ms): 239.27999999996172
// Lodash(ms): 2.710000000070431
まとめ
eachやmapなど単純な処理を行いたい時は純粋なJavaScriptの方がパフォーマンスがいいので、わざわざLodashを使用しなくてもいいかなと思いました。
ただ、flattenなどの純粋JavaScriptで実現しようとすると処理がネストになったりするような、ちょっと複雑なことをしたい時はLodashの方が早いケースもあり、かつ可読性も上がるなと思いました。
うまく使い分けて行きたいです!
明日は、寿司好きフロントエンジニア金子さんです!
お願いします🍣