LoginSignup
38
17

More than 5 years have passed since last update.

WebAssemblyで実装された仮想DOM asm-dom をさわってみた

Last updated at Posted at 2017-12-13

asm-domとは

asm-domはWebAssemblyで実装された仮想DOMライブラリです。
仮想DOMのdiff、patch部分のアルゴリズムをWebAssemblyに任せたミニマルな実装なので、Reactのような多彩な機能はないようです。WebAssemblyなので、爆速を期待してしまいます。

最初のコミットが2017/2/26なのでまだ一年も経っていないライブラリです。
ライセンスの表記snabbdomの名前があるので何か関係があるのかもしれません。

Simon Friis Vindum, 2015 as part of project snabbdom

使い方

C++でも書けるようなのですが、今回はwebらしくjsで使ってみました。

npm i --save asm-dom
npm i -D arraybuffer-loader

webpackでバンドルするので、webpackとwebpack-dev-serverも入れます。

npm i -D webpack webpack-dev-server

webpack.config.jsはこんな感じ。.wasmファイルを読み込むためにarraybuffer-loaderを足しています。

var resolve = require('path').resolve;

module.exports = env => {
  const dist = env.prod ? 'docs' : 'dist';
  return {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: resolve(__dirname, dist),
      pathinfo: !env.prod,
    },
    node: {
      fs: 'empty'
    },
    devtool: env.prod ? 'source-map' : 'eval',
    devServer: {
      contentBase: resolve(__dirname, dist),
      historyApiFallback: true,
      compress: true,
      port: 9000
    },
    module: {
      loaders: [
        {
          test: /\.wasm$/,
          loaders: ['arraybuffer-loader']
        }
      ]
    }
  };
}

JSでの使い方の軽いドキュメントがあるので、それに沿った形です。

virtual-domとの速度を比べてみた

仮想DOMライブラリであるvirtual-domとasm-domの速度を比べてみました。
30000個のdivのテキストをランダムな数値で入れ替えて時間を吐き出してみました。
仕様ブラウザは Chromeでバージョン61 です。

圧倒的にasm-domの方が速かった

その差は約2倍でした。ここまで差が出るとは思いませんでした。さすがWebAssembly。virtual-domがそもそも遅いのかと疑ってしまいたくなります。Reactとかとも純粋なdiff, patchの処理だけで速度を比べてみたいです。

asm-domの計測結果
asm-dom.png
virtual-domの計測結果
virtual-dom.png

計測コード

コードはgithubのレポジトリに置いておきました。
DOMの定義の仕方はhyperscript風なので、virtual-domと同じようにh()でノードを作ってpatch()で変更を適応します。

asm-dom
import init from 'asm-dom';

init().then(asmDom => {
  const { h, patch } = asmDom;

  const root = document.getElementById('root');

  let vnode = h('div', {}, []);
  patch(root, vnode);

  let cnt = 0;
  const id = setInterval(() => {
    console.time('apply patch in 30000 elements');
    const list = [];
    for (let i = 0; i < 30000; i++) {
      list.push(
        h('div', {}, [ Math.random() + '' ])
      );
    }
    const newVnode = h('div', {}, list);
    patch(vnode, newVnode);
    vnode = newVnode;
    console.timeEnd('apply patch in 30000 elements');
    cnt++;
    if (cnt >= 10) {
      clearInterval(id);
    }
  }, 100);
});
virtual-dom
const h = require('virtual-dom/h');
const diff = require('virtual-dom/diff');
const patch = require('virtual-dom/patch');
const createElement = require('virtual-dom/create-element');

let cnt = 0;
let tree = h('div', {}, []);
let rootNode = createElement(tree);
document.body.appendChild(rootNode);

const id = setInterval(function () {
  console.time('apply patch in 30000 elements');
  const list = [];
  for (let i = 0; i < 30000; i++) {
    list.push(
    h('div', {}, [ Math.random() + '' ])
    );
  }
  const newTree = h('div', {}, list);
  const patches = diff(tree, newTree);
  rootNode = patch(rootNode, patches);
  tree = newTree;
  console.timeEnd('apply patch in 30000 elements');
  cnt++;
  if (cnt >= 10) {
    clearInterval(id);
  }
}, 1000);

Web Componentsも試してみました。
WebAssemblyで実装された仮想DOM asm-dom でWeb Componentsを使ってみた

38
17
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
38
17