Skip to content

Commit 032a0de

Browse files
committed
perf tuning
1 parent 7b24395 commit 032a0de

File tree

8 files changed

+87
-72
lines changed

8 files changed

+87
-72
lines changed

src/compiler.js

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ var Emitter = require('./emitter'),
1111

1212
// cache methods
1313
slice = [].slice,
14-
each = [].forEach,
1514
makeHash = utils.hash,
1615
extend = utils.extend,
1716
def = utils.defProtected,
@@ -27,7 +26,7 @@ var Emitter = require('./emitter'),
2726
// list of priority directives
2827
// that needs to be checked in specific order
2928
priorityDirectives = [
30-
'i' + 'f',
29+
'if',
3130
'repeat',
3231
'view',
3332
'component'
@@ -39,7 +38,8 @@ var Emitter = require('./emitter'),
3938
*/
4039
function Compiler (vm, options) {
4140

42-
var compiler = this
41+
var compiler = this,
42+
key, i
4343

4444
// default state
4545
compiler.init = true
@@ -94,17 +94,22 @@ function Compiler (vm, options) {
9494
// create bindings for computed properties
9595
var computed = options.computed
9696
if (computed) {
97-
for (var key in computed) {
97+
for (key in computed) {
9898
compiler.createBinding(key)
9999
}
100100
}
101101

102102
// copy paramAttributes
103-
if (options.paramAttributes) {
104-
options.paramAttributes.forEach(function (attr) {
105-
var val = compiler.eval(el.getAttribute(attr))
106-
vm[attr] = utils.checkNumber(val)
107-
})
103+
var params = options.paramAttributes
104+
if (params) {
105+
i = params.length
106+
while (i--) {
107+
vm[params[i]] = utils.checkNumber(
108+
compiler.eval(
109+
el.getAttribute(params[i])
110+
)
111+
)
112+
}
108113
}
109114

110115
// beforeCompile hook
@@ -131,9 +136,10 @@ function Compiler (vm, options) {
131136
compiler.compile(el, true)
132137

133138
// bind deferred directives (child components)
134-
compiler.deferred.forEach(function (dir) {
135-
compiler.bindDirective(dir)
136-
})
139+
i = compiler.deferred.length
140+
while (i--) {
141+
compiler.bindDirective(compiler.deferred[i])
142+
}
137143

138144
// extract dependencies for computed properties
139145
compiler.parseDeps()
@@ -158,27 +164,32 @@ CompilerProto.setupElement = function (options) {
158164
? document.querySelector(options.el)
159165
: options.el || document.createElement(options.tagName || 'div')
160166

161-
var template = options.template
167+
var template = options.template,
168+
child, frag, replacer, i, attr, attrs
169+
162170
if (template) {
163171
// collect anything already in there
164172
/* jshint boss: true */
165-
var child,
166-
frag = this.rawContent = document.createDocumentFragment()
173+
frag = this.rawContent = document.createDocumentFragment()
167174
while (child = el.firstChild) {
168175
frag.appendChild(child)
169176
}
170177
// replace option: use the first node in
171178
// the template directly
172179
if (options.replace && template.childNodes.length === 1) {
173-
var replacer = template.childNodes[0].cloneNode(true)
180+
replacer = template.childNodes[0].cloneNode(true)
174181
if (el.parentNode) {
175182
el.parentNode.insertBefore(replacer, el)
176183
el.parentNode.removeChild(el)
177184
}
178185
// copy over attributes
179-
each.call(el.attributes, function (attr) {
180-
replacer.setAttribute(attr.name, attr.value)
181-
})
186+
if (el.hasAttributes()) {
187+
i = el.attributes.length
188+
while (i--) {
189+
attr = el.attributes[i]
190+
replacer.setAttribute(attr.name, attr.value)
191+
}
192+
}
182193
// replace
183194
el = replacer
184195
} else {
@@ -189,9 +200,9 @@ CompilerProto.setupElement = function (options) {
189200
// apply element options
190201
if (options.id) el.id = options.id
191202
if (options.className) el.className = options.className
192-
var attrs = options.attributes
203+
attrs = options.attributes
193204
if (attrs) {
194-
for (var attr in attrs) {
205+
for (attr in attrs) {
195206
el.setAttribute(attr, attrs[attr])
196207
}
197208
}
@@ -224,19 +235,21 @@ CompilerProto.setupObserver = function () {
224235
.on('mutate', onSet)
225236

226237
// register hooks
227-
hooks.forEach(function (hook) {
228-
var fns = options[hook]
238+
var i = hooks.length, j, hook, fns
239+
while (i--) {
240+
hook = hooks[i]
241+
fns = options[hook]
229242
if (Array.isArray(fns)) {
230-
var i = fns.length
243+
j = fns.length
231244
// since hooks were merged with child at head,
232245
// we loop reversely.
233-
while (i--) {
234-
registerHook(hook, fns[i])
246+
while (j--) {
247+
registerHook(hook, fns[j])
235248
}
236249
} else if (fns) {
237250
registerHook(hook, fns)
238251
}
239-
})
252+
}
240253

241254
// broadcast attached/detached hooks
242255
observer
@@ -300,8 +313,7 @@ CompilerProto.observeData = function (data) {
300313
$dataBinding.update(data)
301314

302315
// allow $data to be swapped
303-
defGetSet(compiler.vm, '$data', {
304-
enumerable: false,
316+
Object.defineProperty(compiler.vm, '$data', {
305317
get: function () {
306318
compiler.observer.emit('get', '$data')
307319
return compiler.data
@@ -622,7 +634,7 @@ CompilerProto.defineProp = function (key, binding) {
622634

623635
binding.value = data[key]
624636

625-
defGetSet(compiler.vm, key, {
637+
Object.defineProperty(compiler.vm, key, {
626638
get: function () {
627639
return compiler.data[key]
628640
},
@@ -640,14 +652,14 @@ CompilerProto.defineProp = function (key, binding) {
640652
CompilerProto.defineMeta = function (key, binding) {
641653
var vm = this.vm,
642654
ob = this.observer,
643-
value = binding.value = key in vm
655+
value = binding.value = hasOwn.call(vm, key)
644656
? vm[key]
645657
: this.data[key]
646658
// remove initital meta in data, since the same piece
647659
// of data can be observed by different VMs, each have
648660
// its own associated meta info.
649661
delete this.data[key]
650-
defGetSet(vm, key, {
662+
Object.defineProperty(vm, key, {
651663
get: function () {
652664
if (Observer.shouldGet) ob.emit('get', key)
653665
return value
@@ -676,7 +688,7 @@ CompilerProto.defineExp = function (key, binding, directive) {
676688
*/
677689
CompilerProto.defineComputed = function (key, binding, value) {
678690
this.markComputed(binding, value)
679-
defGetSet(this.vm, key, {
691+
Object.defineProperty(this.vm, key, {
680692
get: binding.value.$get,
681693
set: binding.value.$set
682694
})
@@ -884,11 +896,4 @@ function getRoot (compiler) {
884896
return compiler
885897
}
886898

887-
/**
888-
* for convenience & minification
889-
*/
890-
function defGetSet (obj, key, def) {
891-
Object.defineProperty(obj, key, def)
892-
}
893-
894899
module.exports = Compiler

src/directives/repeat.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = {
55

66
bind: function () {
77

8-
this.identifier = '$repeat' + this.id
8+
this.identifier = '$r' + this.id
99

1010
var el = this.el,
1111
ctn = this.container = el.parentNode
@@ -106,7 +106,7 @@ module.exports = {
106106
item = newCollection[i]
107107
if (isObject) {
108108
item.$index = i
109-
if (item[this.identifier]) {
109+
if (item.__emitter__ && item.__emitter__[this.identifier]) {
110110
// this piece of data is being reused.
111111
// record its final position in reused vms
112112
item.$reused = true
@@ -145,7 +145,7 @@ module.exports = {
145145
vms[vm.$index] = vm
146146
} else {
147147
// this one can be destroyed.
148-
delete item[this.identifier]
148+
delete item.__emitter__[this.identifier]
149149
vm.$destroy()
150150
}
151151
}
@@ -215,7 +215,7 @@ module.exports = {
215215
})
216216

217217
// attach an ienumerable identifier
218-
utils.defProtected(data, this.identifier, true)
218+
data.__emitter__[this.identifier] = true
219219
vm.$index = index
220220

221221
if (wrap) {

src/emitter.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ function Emitter () {
22
this._ctx = this
33
}
44

5-
var EmitterProto = Emitter.prototype,
6-
slice = [].slice
5+
var EmitterProto = Emitter.prototype
76

87
EmitterProto.on = function(event, fn){
98
this._cbs = this._cbs || {}
@@ -16,7 +15,7 @@ Emitter.prototype.once = function(event, fn){
1615
var self = this
1716
this._cbs = this._cbs || {}
1817

19-
function on() {
18+
function on () {
2019
self.off(event, on)
2120
fn.apply(this, arguments)
2221
}
@@ -57,15 +56,14 @@ Emitter.prototype.off = function(event, fn){
5756
return this
5857
}
5958

60-
Emitter.prototype.emit = function(event){
59+
Emitter.prototype.emit = function(event, a, b, c){
6160
this._cbs = this._cbs || {}
62-
var args = slice.call(arguments, 1),
63-
callbacks = this._cbs[event]
61+
var callbacks = this._cbs[event]
6462

6563
if (callbacks) {
6664
callbacks = callbacks.slice(0)
6765
for (var i = 0, len = callbacks.length; i < len; i++) {
68-
callbacks[i].apply(this._ctx, args)
66+
callbacks[i].call(this._ctx, a, b, c)
6967
}
7068
}
7169

src/exp-parser.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,10 @@ exports.parse = function (exp, compiler, data, filters) {
156156

157157
// wrap expression with computed filters
158158
if (filters) {
159-
filters.forEach(function (filter) {
160-
var args = filter.args
159+
var args, filter
160+
for (var i = 0, l = filters.length; i < l; i++) {
161+
filter = filters[i]
162+
args = filter.args
161163
? ',"' + filter.args.map(escapeQuote).join('","') + '"'
162164
: ''
163165
body =
@@ -166,7 +168,7 @@ exports.parse = function (exp, compiler, data, filters) {
166168
'").call(this,' +
167169
body + args +
168170
')'
169-
})
171+
}
170172
}
171173

172174
body = accessors + 'return ' + body

src/filters.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ var filters = module.exports = {
9898
}
9999

100100
// get the search string
101-
var search = stripQuotes(searchKey) || get(this, searchKey)
101+
var search = stripQuotes(searchKey) || this.$get(searchKey)
102102
if (!search) return arr
103103
search = search.toLowerCase()
104104

105105
// get the optional dataKey
106-
dataKey = dataKey && (stripQuotes(dataKey) || get(this, dataKey))
106+
dataKey = dataKey && (stripQuotes(dataKey) || this.$get(dataKey))
107107

108108
// convert object to array
109109
if (!Array.isArray(arr)) {
@@ -120,7 +120,7 @@ var filters = module.exports = {
120120

121121
orderBy: function (arr, sortKey, reverseKey) {
122122

123-
var key = stripQuotes(sortKey) || get(this, sortKey)
123+
var key = stripQuotes(sortKey) || this.$get(sortKey)
124124
if (!key) return arr
125125

126126
// convert object to array
@@ -134,9 +134,9 @@ var filters = module.exports = {
134134
order = -1
135135
} else if (reverseKey.charAt(0) === '!') {
136136
reverseKey = reverseKey.slice(1)
137-
order = get(this, reverseKey) ? 1 : -1
137+
order = this.$get(reverseKey) ? 1 : -1
138138
} else {
139-
order = get(this, reverseKey) ? -1 : 1
139+
order = this.$get(reverseKey) ? -1 : 1
140140
}
141141
}
142142

src/observer.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var Emitter = require('./emitter'),
55
// cache methods
66
typeOf = utils.typeOf,
77
def = utils.defProtected,
8+
hasOwn = ({}).hasOwnProperty,
89
slice = [].slice,
910
// types
1011
OBJECT = 'Object',
@@ -134,15 +135,15 @@ function unlinkArrayElements (arr, items) {
134135
var ObjProxy = Object.create(Object.prototype)
135136

136137
def(ObjProxy, '$add', function (key, val) {
137-
if (key in this) return
138+
if (hasOwn.call(this, key)) return
138139
this[key] = val
139140
convertKey(this, key)
140141
// emit a propagating set event
141142
this.__emitter__.emit('set', key, val, true)
142143
}, !hasProto)
143144

144145
def(ObjProxy, '$delete', function (key) {
145-
if (!(key in this)) return
146+
if (!(hasOwn.call(this, key))) return
146147
// trigger set events
147148
this[key] = undefined
148149
delete this[key]
@@ -315,7 +316,7 @@ function copyPaths (newObj, oldObj) {
315316
}
316317
var path, type, oldVal, newVal
317318
for (path in oldObj) {
318-
if (!(path in newObj)) {
319+
if (!(hasOwn.call(newObj, path))) {
319320
oldVal = oldObj[path]
320321
type = typeOf(oldVal)
321322
if (type === OBJECT) {
@@ -346,7 +347,7 @@ function ensurePath (obj, key) {
346347
}
347348
if (typeOf(obj) === OBJECT) {
348349
sec = path[i]
349-
if (!(sec in obj)) {
350+
if (!(hasOwn.call(obj, sec))) {
350351
obj[sec] = undefined
351352
if (obj.__emitter__) convertKey(obj, sec)
352353
}

src/utils.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,10 @@ var utils = module.exports = {
8080
* or for...in loops.
8181
*/
8282
defProtected: function (obj, key, val, enumerable, writable) {
83-
if (obj.hasOwnProperty(key)) return
8483
Object.defineProperty(obj, key, {
8584
value : val,
86-
enumerable : !!enumerable,
87-
writable : !!writable,
85+
enumerable : enumerable,
86+
writable : writable,
8887
configurable : true
8988
})
9089
},

0 commit comments

Comments
 (0)