LoginSignup
1
0

More than 3 years have passed since last update.

[Node.js][Deno] オブジェクト合成各種 ベンチマーク比較

Posted at

先ほどの クラスのベンチマーク の続編。
オブジェクト合成でより良い(というか速い)手法ないかなと悩みつつ。

実験環境

同じく

  • Node.js 14.15.1
  • Deno 1.5.4

実験設定

  • 10要素で構成されるオブジェクト2組を1つのオブジェクトにまとめる
  • 要素のうち5つは名前が重複しており、合成元を合成先に上書きする
  • 合成先はプロトタイプではなく、独立したオブジェクトとして新規に生成される

という前提で

  • 合成先オブジェクトを生成するファンクションと、合成元オブジェクトを用意
  • 実行時間計測
    • 合成先オブジェクト生成ファンクションだけの結果
    • 合成先オブジェクト生成ファンクション+各種アルゴリズムの結果
  • 結果表示
    • 各種アルゴリズムの結果部分を抽出表示

という手順。

オブジェクト合成アルゴリズム ここに集う

今回調査するアルゴリズムを御紹介いたしましょう。

assign
Object.assign()
spread
スプレッド構文
for
for inループ
forEach
keys forEachコールバック
map
keys mapコールバック
entries
entries列挙ループ
lowtech1
(対照用) オブジェクト要素として個別に代入
lowtech2
(対照用) 連想配列要素として個別に代入

多少のオーバーヘッドは仕方ないにしても、できるだけ対照用で挙げた方法に
近い(というか速い)アルゴリズムを採用したいという趣旨。

いざ、実験

今回は記述がコンパクトなので、1ソースでまとめていけます

bench_obj_merge.js
function CreateParent(){return {a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,i:8,j:9};}
var sub={f:10,g:11,h:12,i:13,j:14,k:15,l:16,m:17,n:18,o:19};

// 実行内容 
var funx={
    dmy:()=>0, // 最初の実行項目は不利な結果が出るのでダミー 
    create:()=>CreateParent(),
    assign:()=>Object.assign(CreateParent(),sub),
    spread:()=>{return {...CreateParent(),...sub};},
    for:()=>{
        var t=CreateParent();
        for(var k in sub)t[k]=sub[k];
        return t;
    },
    forEach:()=>{
        var t=CreateParent();
        Object.keys(sub).forEach(k=>t[k]=sub[k]);
        return t;
    },
    map:()=>{
        var t=CreateParent();
        Object.keys(sub).map(k=>t[k]=sub[k]);
        return t;
    },
    entries:()=>{
        var t=CreateParent();
        for(var [k,v] of Object.entries(sub))t[k]=v;
        return t;
    },
    lowtech1:()=>{
        var t=CreateParent();
        t.f=sub.f;
        t.g=sub.g;
        t.h=sub.h;
        t.i=sub.i;
        t.j=sub.j;
        t.k=sub.k;
        t.l=sub.l;
        t.m=sub.m;
        t.n=sub.n;
        t.o=sub.o;
        return t;
    },
    lowtech2:()=>{
        var t=CreateParent();
        t['f']=sub['f'];
        t['g']=sub['g'];
        t['h']=sub['h'];
        t['i']=sub['i'];
        t['j']=sub['j'];
        t['k']=sub['k'];
        t['l']=sub['l'];
        t['m']=sub['m'];
        t['n']=sub['n'];
        t['o']=sub['o'];
        return t;
    },
};
// 計測結果を書き込むところ 
var rec={};

// 動作テスト 
//for(var k in funx)console.log([k,funx[k]()]);

// 繰り返し実行時間計測 
var loop=Array(1000000);
for(var k in funx){
    var f=funx[k];
    var bgn=new Date;
    for(var i of loop)f();
    var end=new Date;
    rec[k]=(end-bgn);
}

// 結果表示 
for(var k in rec)console.log(k+' :'+(rec[k]-rec.create));

ここで予想外の事態。当初は 前回 と同じ1千万ループだったのですが、なかなか処理終わらなかったので一旦止めて桁減らしちゃいました。
それでループ回数が1桁減っているので、前回の結果と比べるときは御注意ください。

Node.js Deno
assign 255.7 265.4
spread 6906.3 6503.3
for 289.2 484.4
forEach 413.6 463.1
map 445.5 505.7
entries 417.3 428.4
lowtech1 10.1 8
lowtech2 10.3 8

まず目を疑ったのが、今(一部で)流行りのスプレッド構文、なんと1桁遅い。
記述が一番シンプルなだけに残念なところ。
で、とりあえず Object.assign() がベストというか幾分マシということで。
もっと素敵な手法ないものかしらん。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0