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の処理だけで速度を比べてみたいです。
計測コード
コードはgithubのレポジトリに置いておきました。
DOMの定義の仕方はhyperscript風なので、virtual-domと同じようにh()
でノードを作ってpatch()
で変更を適応します。
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);
});
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を使ってみた』