Skip to content

Commit

Permalink
Merge 73cbb60 into 58d43f5
Browse files Browse the repository at this point in the history
  • Loading branch information
mbasso committed Apr 24, 2018
2 parents 58d43f5 + 73cbb60 commit 2bd5a62
Show file tree
Hide file tree
Showing 76 changed files with 2,350 additions and 1,323 deletions.
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ node_js:
- "8"
- "9"
install: true
sudo: required
services:
- docker
before_install:
- docker run -dit --name emscripten -v $(pwd):/src trzeci/emscripten:sdk-incoming-64bit bash
script:
- npm install --ignore-scripts
- docker exec -it emscripten npm run compile
- npm run lint
- npm run test:js
- npm run build
Expand All @@ -32,4 +38,5 @@ jobs:
branches:
only:
- master
if: tag =~ ^\d+\.\d+\.\d+
after_success: echo "Website online"
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ Also, here is the list of the online Demos:

## Roadmap

- [ ] create asm-dom boilerplate
- [ ] Thunks support
- [ ] asm-dom aims to be even more powerful with [GC/DOM Integration](http://webassembly.org/docs/future-features/). Unfortunately this is a future feature 🦄, so, we have to be patient and wait a bit.

Expand Down
6 changes: 3 additions & 3 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ There are 4 tests at the moment:

- `create nodes`: this test create 700 nodes (100 nodes with 3 children, the last of which has 3 more children). Please note that, as we said before, **in the case of asm-dom, this test creates but also destroys the nodes**. While, in the case of snabbdom, the deletion is managed by the garbage collector and it is not measured.

- `create and diff equal nodes`: this test runs the `patch` function 100 times with 2 equal nodes (2 nodes with 100 children, each of them has 1 child), so, the DOM will be not updated.
- `diff equal nodes`: this test runs the `patch` function 100 times with 2 equal nodes (2 nodes with 100 children, each of them has 1 child), so, the DOM will be not updated.

- `create and diff different nodes`: this test runs the `patch` function 100 times with 2 nodes with different attributes (2 nodes with 100 children, each of them has 1 child), so, the DOM will be updated.
- `diff different nodes`: this test runs the `patch` function 100 times with 2 nodes with different attributes (2 nodes with 100 children, each of them has 1 child), so, the DOM will be updated.

- `create and add/remove nodes`: this test runs the `patch` function 100 times with 2 nodes, one with 100 children and one without children.
- `add/remove nodes`: this test runs the `patch` function 100 times with 2 nodes, one with 100 children and one without children.

Here you can find screenshots of the tests (lower is better) runned on a MacBook Pro (Retina, 13-inch, Late 2013), Processor 2,4 GHz Intel Core i5, Memory 8 GB 1600 MHz DDR3:

Expand Down
Binary file modified benchmarks/compiled/app.bc
Binary file not shown.
Binary file modified benchmarks/compiled/app.o
Binary file not shown.
138 changes: 69 additions & 69 deletions benchmarks/compiled/asmjs/app.asm.js

Large diffs are not rendered by default.

42 changes: 21 additions & 21 deletions benchmarks/compiled/wasm/app.js

Large diffs are not rendered by default.

Binary file modified benchmarks/compiled/wasm/app.wasm
Binary file not shown.
4 changes: 2 additions & 2 deletions benchmarks/src/index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ int main() {
));
}
for (int i = 0; i < 10000; ++i) {
delete children[i];
deleteVNode(children[i]);
}

return 0;
Expand All @@ -61,7 +61,7 @@ void create() {
})
}
);
delete vnode;
deleteVNode(vnode);
}
};

Expand Down
22 changes: 10 additions & 12 deletions benchmarks/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ const config = {};
import('../compiled/wasm/app.wasm')
.then((wasm) => {
config.wasmBinary = new Uint8Array(wasm);
return new Promise((resolve) => {
import('../compiled/wasm/app.js').then(factory => {
const asmDom = factory(config);
delete asmDom.then;
resolve(asmDom);
});
return import('../compiled/wasm/app.js').then(factory => {
const asmDom = factory(config);
delete asmDom.then;
return asmDom;
});
})
.then((app) => {
Expand All @@ -48,19 +46,19 @@ import('../compiled/wasm/app.wasm')
message: 'create nodes',
fn: asmdomCpp.create,
}, {
message: 'create and diff equal nodes',
message: 'diff equal nodes',
setup: function () {
asmdomCpp.patchWithoutChangesSetup();
},
fn: asmdomCpp.patchWithoutChanges,
}, {
message: 'create and diff different nodes',
message: 'diff different nodes',
setup: function () {
asmdomCpp.patchWithChangesSetup();
},
fn: asmdomCpp.patchWithChanges,
}, {
message: 'create and add/remove nodes',
message: 'add/remove nodes',
setup: function () {
asmdomCpp.patchWithAdditionSetup();
},
Expand Down Expand Up @@ -89,7 +87,7 @@ import('../compiled/wasm/app.wasm')
}
},
}, {
message: 'create and diff equal nodes',
message: 'diff equal nodes',
setup: function() {
var elm = document.getElementById('root');
var children = [];
Expand Down Expand Up @@ -140,7 +138,7 @@ import('../compiled/wasm/app.wasm')
}
},
}, {
message: 'create and diff different nodes',
message: 'diff different nodes',
setup: function() {
const elm = document.getElementById('root');
var children = [];
Expand Down Expand Up @@ -191,7 +189,7 @@ import('../compiled/wasm/app.wasm')
}
},
}, {
message: 'create and add/remove nodes',
message: 'add/remove nodes',
setup: function() {
var elm = document.getElementById('root');
var children = [];
Expand Down
Binary file modified compiled/asm-dom.a
Binary file not shown.
Binary file modified compiled/asm-dom.bc
Binary file not shown.
Binary file modified compiled/asm-dom.o
Binary file not shown.
190 changes: 96 additions & 94 deletions compiled/asmjs/asm-dom.asm.js

Large diffs are not rendered by default.

166 changes: 84 additions & 82 deletions compiled/wasm/asm-dom.js

Large diffs are not rendered by default.

Binary file modified compiled/wasm/asm-dom.wasm
Binary file not shown.
93 changes: 54 additions & 39 deletions cpp/Diff/diff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,30 @@
namespace asmdom {

const std::string emptyString;
const std::string trueString = "true";
const std::string falseString = "false";

void diffAttrs(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
if (oldVnode->data.attrs.empty() && vnode->data.attrs.empty()) return;
Attrs& oldAttrs = oldVnode->data.attrs;
Attrs& attrs = vnode->data.attrs;

for (auto& it : oldVnode->data.attrs) {
if (!vnode->data.attrs.count(it.first)) {
for (const auto& it : oldAttrs) {
if (!attrs.count(it.first)) {
EM_ASM_({
window['asmDomHelpers']['domApi']['removeAttribute'](
Module.removeAttribute(
$0,
Module['UTF8ToString']($1)
);
}, vnode->elm, it.first.c_str());
}
}

for (auto& it : vnode->data.attrs) {
if (!oldVnode->data.attrs.count(it.first) || oldVnode->data.attrs[it.first] != it.second) {
for (const auto& it : attrs) {
if (!oldAttrs.count(it.first) || oldAttrs[it.first] != it.second) {
#ifndef ASMDOM_JS_SIDE
if (it.second == "false") {
if (it.second == falseString) {
EM_ASM_({
window['asmDomHelpers']['domApi']['removeAttribute'](
Module.removeAttribute(
$0,
Module['UTF8ToString']($1)
);
Expand All @@ -38,12 +41,12 @@ namespace asmdom {
#endif

EM_ASM_({
window['asmDomHelpers']['domApi']['setAttribute'](
Module.setAttribute(
$0,
Module['UTF8ToString']($1),
Module['UTF8ToString']($2)
);
}, vnode->elm, it.first.c_str(), it.second == "true" ? emptyString.c_str() : it.second.c_str());
}, vnode->elm, it.first.c_str(), it.second == trueString ? emptyString.c_str() : it.second.c_str());

#ifndef ASMDOM_JS_SIDE
}
Expand All @@ -54,29 +57,30 @@ namespace asmdom {

#ifndef ASMDOM_JS_SIDE

void diffProps(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
if (oldVnode->data.props.empty() && vnode->data.props.empty()) return;
void diffProps(const VNode* __restrict__ const oldVnode, const VNode* __restrict__ const vnode) {
const Props& oldProps = oldVnode->data.props;
const Props& props = vnode->data.props;

emscripten::val elm = emscripten::val::global("window")["asmDomHelpers"]["nodes"][vnode->elm];

EM_ASM_({
window['asmDomHelpers']['nodes'][$0]['asmDomRaws'] = [];
Module.nodes[$0]['asmDomRaws'] = [];
}, vnode->elm);

for (auto& it : oldVnode->data.props) {
if (!vnode->data.props.count(it.first)) {
for (const auto& it : oldProps) {
if (!props.count(it.first)) {
elm.set(it.first.c_str(), emscripten::val::undefined());
}
}

for (auto& it : vnode->data.props) {
for (const auto& it : props) {
EM_ASM_({
window['asmDomHelpers']['nodes'][$0]['asmDomRaws'].push(Module['UTF8ToString']($1));
Module.nodes[$0]['asmDomRaws'].push(Module['UTF8ToString']($1));
}, vnode->elm, it.first.c_str());

if (
!oldVnode->data.props.count(it.first) ||
!it.second.strictlyEquals(oldVnode->data.props.at(it.first)) ||
!oldProps.count(it.first) ||
!it.second.strictlyEquals(oldProps.at(it.first)) ||
(
(it.first == "value" || it.first == "checked") &&
!it.second.strictlyEquals(elm[it.first.c_str()])
Expand All @@ -87,17 +91,18 @@ namespace asmdom {
}
};

void diffCallbacks(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
if (oldVnode->data.callbacks.empty() && vnode->data.callbacks.empty()) return;
void diffCallbacks(const VNode* __restrict__ const oldVnode, const VNode* __restrict__ const vnode) {
const Callbacks& oldCallbacks = oldVnode->data.callbacks;
const Callbacks& callbacks = vnode->data.callbacks;

for (auto& it : oldVnode->data.callbacks) {
if (!vnode->data.callbacks.count(it.first)) {
for (const auto& it : oldCallbacks) {
if (!callbacks.count(it.first) && it.first != "ref") {
EM_ASM_({
var key = Module['UTF8ToString']($1).replace(/^on/, "");
var elm = window['asmDomHelpers']['nodes'][$0];
var elm = Module.nodes[$0];
elm.removeEventListener(
key,
window['asmDomHelpers']['eventProxy'],
Module.eventProxy,
false
);
delete elm['asmDomEvents'][key];
Expand All @@ -106,43 +111,53 @@ namespace asmdom {
}

EM_ASM_({
var elm = window['asmDomHelpers']['nodes'][$0];
var elm = Module.nodes[$0];
elm.asmDomVNode = $1;
if (elm['asmDomEvents'] === undefined) {
elm['asmDomEvents'] = {};
}
}, vnode->elm, reinterpret_cast<std::uintptr_t>(vnode));

for (auto& it : vnode->data.callbacks) {
if (!oldVnode->data.callbacks.count(it.first)) {
for (const auto& it : callbacks) {
if (!oldCallbacks.count(it.first) && it.first != "ref") {
EM_ASM_({
var key = Module['UTF8ToString']($1).replace(/^on/, "");
var elm = window['asmDomHelpers']['nodes'][$0];
var elm = Module.nodes[$0];
elm.addEventListener(
key,
window['asmDomHelpers']['eventProxy'],
Module.eventProxy,
false
);
elm['asmDomEvents'][key] = window['asmDomHelpers']['eventProxy'];
elm['asmDomEvents'][key] = Module.eventProxy;
}, vnode->elm, it.first.c_str());
}
}

if (vnode->hash & hasRef) {
bool(*const* callback)(emscripten::val) = callbacks.at("ref").target<bool(*)(emscripten::val)>();
bool(*const* oldCallback)(emscripten::val) = oldVnode->hash & hasRef ? oldCallbacks.at("ref").target<bool(*)(emscripten::val)>() : NULL;
if (callback == NULL || oldCallback == NULL || *oldCallback != *callback) {
callbacks.at("ref")(
emscripten::val::global("window")["asmDomHelpers"]["nodes"][vnode->elm]
);
}
}
};

#endif

void diff(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
const unsigned int vnodes = vnode->hash | oldVnode->hash;

if (vnodes & hasAttrs) diffAttrs(oldVnode, vnode);

#ifdef ASMDOM_JS_SIDE
EM_ASM_({
window['asmDomHelpers']['diff']($0, $1, $2);
Module.diff($0, $1, $2);
}, reinterpret_cast<std::uintptr_t>(oldVnode), reinterpret_cast<std::uintptr_t>(vnode), vnode->elm);
#endif

diffAttrs(oldVnode, vnode);

#ifndef ASMDOM_JS_SIDE
diffProps(oldVnode, vnode);
diffCallbacks(oldVnode, vnode);
#else
if (vnodes & hasProps) diffProps(oldVnode, vnode);
if (vnodes & hasCallbacks) diffCallbacks(oldVnode, vnode);
#endif
};

Expand Down
28 changes: 23 additions & 5 deletions cpp/Init/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,33 @@ namespace asmdom {
vdomconfig.setClearMemory(config.clearMemory);
vdomconfig.setUnsafePatch(config.unsafePatch);

#ifndef ASMDOM_JS_SIDE

EM_ASM(
EM_ASM(
#ifndef ASMDOM_JS_SIDE
window['asmDomHelpers']['eventProxy'] = function(e) {
return Module['functionCallback'](this.asmDomVNode, e.type, e)
};
);
#else
Module.diff = window['asmDomHelpers']['diff'];
#endif

Module.addNode = window['asmDomHelpers']['domApi']['addNode'];
Module.createElement = window['asmDomHelpers']['domApi']['createElement'];
Module.createElementNS = window['asmDomHelpers']['domApi']['createElementNS'];
Module.createTextNode = window['asmDomHelpers']['domApi']['createTextNode'];
Module.createComment = window['asmDomHelpers']['domApi']['createComment'];
Module.createDocumentFragment = window['asmDomHelpers']['domApi']['createDocumentFragment'];
Module.insertBefore = window['asmDomHelpers']['domApi']['insertBefore'];
Module.removeChild = window['asmDomHelpers']['domApi']['removeChild'];
Module.appendChild = window['asmDomHelpers']['domApi']['appendChild'];
Module.removeAttribute = window['asmDomHelpers']['domApi']['removeAttribute'];
Module.setAttribute = window['asmDomHelpers']['domApi']['setAttribute'];
Module.parentNode = window['asmDomHelpers']['domApi']['parentNode'];
Module.nextSibling = window['asmDomHelpers']['domApi']['nextSibling'];
Module.setNodeValue = window['asmDomHelpers']['domApi']['setNodeValue'];

#endif
Module.nodes = window['asmDomHelpers']['nodes'];
Module.eventProxy = window['asmDomHelpers']['eventProxy'];
);
};

}
Loading

0 comments on commit 2bd5a62

Please sign in to comment.