aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichał Gołębiowski2013-10-16 15:15:21 +0200
committerIgor Minar2013-12-13 02:07:11 -0800
commit3410f65e790a81d457b4f4601a1e760a6f8ede5e (patch)
tree2f37146f1399d23ea02de44e8209879eda949e1f /src
parentf3de5b6eac90baf649506072162f36dbc6d2f028 (diff)
downloadangular.js-3410f65e790a81d457b4f4601a1e760a6f8ede5e.tar.bz2
perf(jqLite): implement and use the `empty` method in place of `html(‘’)`
jQuery's elem.html('') is way slower than elem.empty(). As clearing element contents happens quite often in certain scenarios, switching to using .empty() provides a significant performance boost when using Angular with jQuery. Closes #4457
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js2
-rw-r--r--src/jqLite.js22
-rw-r--r--src/ng/compile.js4
-rw-r--r--src/ng/directive/ngTransclude.js2
-rw-r--r--src/ng/directive/select.js4
-rw-r--r--src/ngAnimate/animate.js2
6 files changed, 25 insertions, 11 deletions
diff --git a/src/Angular.js b/src/Angular.js
index b09d3a7f..e32c3739 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -974,7 +974,7 @@ function startingTag(element) {
try {
// turns out IE does not let you set .html() on elements which
// are not allowed to have children. So we just ignore it.
- element.html('');
+ element.empty();
} catch(e) {}
// As Per DOM Standards
var TEXT_NODE = 3;
diff --git a/src/jqLite.js b/src/jqLite.js
index e7531fb3..8a45f966 100644
--- a/src/jqLite.js
+++ b/src/jqLite.js
@@ -46,6 +46,7 @@
* - [`contents()`](http://api.jquery.com/contents/)
* - [`css()`](http://api.jquery.com/css/)
* - [`data()`](http://api.jquery.com/data/)
+ * - [`empty()`](http://api.jquery.com/empty/)
* - [`eq()`](http://api.jquery.com/eq/)
* - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
* - [`hasClass()`](http://api.jquery.com/hasClass/)
@@ -358,6 +359,15 @@ function jqLiteInheritedData(element, name, value) {
}
}
+function jqLiteEmpty(element) {
+ for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
+ jqLiteDealoc(childNodes[i]);
+ }
+ while (element.firstChild) {
+ element.removeChild(element.firstChild);
+ }
+}
+
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
@@ -552,7 +562,9 @@ forEach({
jqLiteDealoc(childNodes[i]);
}
element.innerHTML = value;
- }
+ },
+
+ empty: jqLiteEmpty
}, function(fn, name){
/**
* Properties: writes return selection, reads return first value
@@ -562,11 +574,13 @@ forEach({
// jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
// in a way that survives minification.
- if (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined) {
+ // jqLiteEmpty takes no arguments but is a setter.
+ if (fn !== jqLiteEmpty &&
+ (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
if (isObject(arg1)) {
// we are a write, but the object properties are the key/values
- for(i=0; i < this.length; i++) {
+ for (i = 0; i < this.length; i++) {
if (fn === jqLiteData) {
// data() takes the whole object in jQuery
fn(this[i], arg1);
@@ -591,7 +605,7 @@ forEach({
}
} else {
// we are a write, so apply to all children
- for(i=0; i < this.length; i++) {
+ for (i = 0; i < this.length; i++) {
fn(this[i], arg1, arg2);
}
// return self for chaining
diff --git a/src/ng/compile.js b/src/ng/compile.js
index a6bcc3e7..0af76a75 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -1219,7 +1219,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
});
} else {
$template = jqLite(jqLiteClone(compileNode)).contents();
- $compileNode.html(''); // clear contents
+ $compileNode.empty(); // clear contents
childTranscludeFn = compile($template, transcludeFn);
}
}
@@ -1651,7 +1651,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
? origAsyncDirective.templateUrl($compileNode, tAttrs)
: origAsyncDirective.templateUrl;
- $compileNode.html('');
+ $compileNode.empty();
$http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
success(function(content) {
diff --git a/src/ng/directive/ngTransclude.js b/src/ng/directive/ngTransclude.js
index 490ea21f..8eefb6ff 100644
--- a/src/ng/directive/ngTransclude.js
+++ b/src/ng/directive/ngTransclude.js
@@ -69,7 +69,7 @@ var ngTranscludeDirective = ngDirective({
link: function($scope, $element, $attrs, controller) {
controller.$transclude(function(clone) {
- $element.html('');
+ $element.empty();
$element.append(clone);
});
}
diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js
index 86e04242..d87fa5d3 100644
--- a/src/ng/directive/select.js
+++ b/src/ng/directive/select.js
@@ -333,13 +333,13 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// becomes the compilation root
nullOption.removeClass('ng-scope');
- // we need to remove it before calling selectElement.html('') because otherwise IE will
+ // we need to remove it before calling selectElement.empty() because otherwise IE will
// remove the label from the element. wtf?
nullOption.remove();
}
// clear contents, we'll add what's needed based on the model
- selectElement.html('');
+ selectElement.empty();
selectElement.on('change', function() {
scope.$apply(function() {
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index 8ff7b429..aeb6e32e 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -1237,7 +1237,7 @@ angular.module('ngAnimate', ['ng'])
//make the element super hidden and override any CSS style values
clone.attr('style','position:absolute; top:-9999px; left:-9999px');
clone.removeAttr('id');
- clone.html('');
+ clone.empty();
forEach(oldClasses.split(' '), function(klass) {
clone.removeClass(klass);