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

@ -2,7 +2,9 @@ var assert = require('assert');
var snabbdom = require('../snabbdom'); var snabbdom = require('../snabbdom');
var h = require('../h').default; var h = require('../h').default;
var patch = snabbdom.init([]); var patch = snabbdom.init([
require('../modules/attributes').default
]);
describe('svg', function () { describe('svg', function () {
var elm, vnode0; var elm, vnode0;
@ -10,6 +12,7 @@ describe('svg', function () {
elm = document.createElement('svg'); elm = document.createElement('svg');
vnode0 = elm; vnode0 = elm;
}); });
it('removes child svg elements', function(){ it('removes child svg elements', function(){
var a = h('svg', {}, [ var a = h('svg', {}, [
h('g'), h('g'),
@ -21,4 +24,30 @@ describe('svg', function () {
var result = patch(patch(vnode0, a), b).elm; var result = patch(patch(vnode0, a), b).elm;
assert.equal(result.childNodes.length, 1); 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