Performance improvement for attribute patching: (#257)

* Performance improvements for attribute patching:
- Avoid call to split and use a object lookup instead
- Simplify the code for `svg` name spaced attributes

* Fix typo and added missing property

* Fixing previous attribute ns assignment

* Refactor NS

* Add fast path for non namespaced elements

* Adding tests
pull/266/head
Diego Ferreiro Val 8 years ago committed by GitHub
parent 6f12fdc9dd
commit 4ede863df2

@ -1,10 +1,6 @@
import {VNode, VNodeData} from '../vnode';
import {Module} from './module';
const NamespaceURIs = {
"xlink": "http://www.w3.org/1999/xlink"
};
const booleanAttrs = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "compact", "controls", "declare",
"default", "defaultchecked", "defaultmuted", "defaultselected", "defer", "disabled", "draggable",
"enabled", "formnovalidate", "hidden", "indeterminate", "inert", "ismap", "itemscope", "loop", "multiple",
@ -12,6 +8,10 @@ const booleanAttrs = ["allowfullscreen", "async", "autofocus", "autoplay", "chec
"required", "reversed", "scoped", "seamless", "selected", "sortable", "spellcheck", "translate",
"truespeed", "typemustmatch", "visible"];
const xlinkNS = 'http://www.w3.org/1999/xlink';
const xmlNS = 'http://www.w3.org/XML/1998/namespace';
const colonChar = 58;
const xChar = 120;
const booleanAttrsDict: {[attribute: string]: boolean} = Object.create(null);
for (let i = 0, len = booleanAttrs.length; i < len; i++) {
@ -21,7 +21,7 @@ for (let i = 0, len = booleanAttrs.length; i < len; i++) {
function updateAttrs(oldVnode: VNode, vnode: VNode): void {
var key: string, elm: Element = vnode.elm as Element,
oldAttrs = (oldVnode.data as VNodeData).attrs,
attrs = (vnode.data as VNodeData).attrs, namespaceSplit: Array<string>;
attrs = (vnode.data as VNodeData).attrs;
if (!oldAttrs && !attrs) return;
if (oldAttrs === attrs) return;
@ -40,9 +40,14 @@ function updateAttrs(oldVnode: VNode, vnode: VNode): void {
elm.removeAttribute(key);
}
} else {
namespaceSplit = key.split(":");
if (namespaceSplit.length > 1 && NamespaceURIs.hasOwnProperty(namespaceSplit[0])) {
elm.setAttributeNS((NamespaceURIs as any)[namespaceSplit[0]], key, cur);
if (key.charCodeAt(0) !== xChar) {
elm.setAttribute(key, cur);
} else if (key.charCodeAt(3) === colonChar) {
// Assume xml namespace
elm.setAttributeNS(xmlNS, key, cur);
} else if (key.charCodeAt(5) === colonChar) {
// Assume xlink namespace
elm.setAttributeNS(xlinkNS, key, cur);
} else {
elm.setAttribute(key, cur);
}

@ -2,7 +2,9 @@ var assert = require('assert');
var snabbdom = require('../snabbdom');
var h = require('../h').default;
var patch = snabbdom.init([]);
var patch = snabbdom.init([
require('../modules/attributes').default
]);
describe('svg', function () {
var elm, vnode0;
@ -10,6 +12,7 @@ describe('svg', function () {
elm = document.createElement('svg');
vnode0 = elm;
});
it('removes child svg elements', function(){
var a = h('svg', {}, [
h('g'),
@ -21,4 +24,30 @@ describe('svg', function () {
var result = patch(patch(vnode0, a), b).elm;
assert.equal(result.childNodes.length, 1);
});
it('adds correctly xlink namespaced attribute', function(){
var xlinkNS = 'http://www.w3.org/1999/xlink';
var testUrl = '/test';
var a = h('svg', {}, [
h('use', {
attrs: { 'xlink:href': testUrl }
}, [])
]);
var result = patch(vnode0, a).elm;
assert.equal(result.childNodes.length, 1);
assert.equal(result.childNodes[0].getAttribute('xlink:href'), testUrl);
assert.equal(result.childNodes[0].getAttributeNS(xlinkNS,'href'), testUrl);
});
it('adds correctly xml namespaced attribute', function(){
var xmlNS = 'http://www.w3.org/XML/1998/namespace';
var testAttrValue = 'und';
var a = h('svg', { attrs: { 'xml:lang': testAttrValue } }, []);
var result = patch(vnode0, a).elm;
assert.equal(result.getAttributeNS(xmlNS, 'lang'), testAttrValue);
assert.equal(result.getAttribute('xml:lang'), testAttrValue);
});
})
Loading…
Cancel
Save