소스 검색

Improve data array speeds

This improves the speeds of creating the `<option>` tags for array
data. By creating the HTML ahead of time and putting it into an
`<option>` element before passing it to jQuery, it cuts down on the
time it takes for jQuery to process the HTML string and convert it
into DOM elements. This proved to be incredibly slow.

This also changes the `item` function to return early when the
data exists. The `$e.data` call has also been switched to a
`$.data` call, which doesn't need to check the DOM to see if the
data attributes already exist. This cuts down on a bit of wasted
time, as the `data` key should never be present in the DOM, and it
should be ignored if it is.
Kevin Brown 10 년 전
부모
커밋
05ddbec1a7
8개의 변경된 파일316개의 추가작업 그리고 210개의 파일을 삭제
  1. 61 42
      dist/js/select2.amd.full.js
  2. 61 42
      dist/js/select2.amd.js
  3. 58 39
      dist/js/select2.full.js
  4. 0 0
      dist/js/select2.full.min.js
  5. 58 39
      dist/js/select2.js
  6. 0 0
      dist/js/select2.min.js
  7. 61 42
      src/js/select2/data/select.js
  8. 17 6
      tests/data/select-tests.js

+ 61 - 42
dist/js/select2.amd.full.js

@@ -1098,68 +1098,87 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var $option = $('<option></option>');
+    var option = document.createElement('option');
 
-    $option.text(data.text);
-    $option.val(data.id);
-    $option.prop('disabled', data.disabled || false);
-    $option.prop('selected', data.selected || false);
+    option.value = data.id;
 
-    // Get any automatically generated data values
-    var detectedData = this.item($option);
+    if (data.disabled) {
+      option.disabled = true;
+    }
+
+    if (data.selected) {
+      option.selected = true;
+    }
 
-    // Merge it with the already present data
-    var combinedData = $.extend({}, data, detectedData);
+    option.innerText = data.text;
+
+    var $option = $(option);
+
+    var normalizedData = this._normalizeItem(data);
 
     // Override the option's data with the combined data
-    $option.data('data', combinedData);
+    $.data($option, normalizedData);
 
     return $option;
   };
 
   SelectAdapter.prototype.item = function ($option) {
-    var data = $option.data('data');
-
-    // If the data has already be generated, use it
-    if (data == null) {
-      if ($option.is('option')) {
-        data = {
-          id: $option.val(),
-          text: $option.html(),
-          disabled: $option.prop('disabled')
-        };
-      } else if ($option.is('optgroup')) {
-        data = {
-          text: $option.attr('label'),
-          children: []
-        };
-
-        var $children = $option.children('option');
-        var children = [];
-
-        for (var c = 0; c < $children.length; c++) {
-          var $child = $($children[c]);
-
-          var child = this.item($child);
-
-          children.push(child);
-        }
+    var data = {};
 
-        data.children = children;
-      }
+    if ($.hasData($option)) {
+      data = $option.data('data');
 
-      if (data.id && this.container != null) {
-        data._resultId = this.generateResultId(this.container, data);
+      if (data != null) {
+        return data;
       }
+    }
+
+    if ($option.is('option')) {
+      data = {
+        id: $option.val(),
+        text: $option.html(),
+        disabled: $option.prop('disabled')
+      };
+    } else if ($option.is('optgroup')) {
+      data = {
+        text: $option.attr('label'),
+        children: []
+      };
+
+      var $children = $option.children('option');
+      var children = [];
 
-      data.selected = $option.prop('selected');
+      for (var c = 0; c < $children.length; c++) {
+        var $child = $($children[c]);
 
-      $option.data('data', data);
+        var child = this.item($child);
+
+        children.push(child);
+      }
+
+      data.children = children;
     }
 
+    data = this._normalizeItem(data);
+
+    $option.data('data', data);
+
     return data;
   };
 
+  SelectAdapter.prototype._normalizeItem = function (item) {
+    var defaults = {
+      selected: false,
+      disabled: false
+    };
+
+    if (item._resultId == null && item.id && this.container != null) {
+      item._resultId = this.generateResultId(this.container, item);
+    }
+
+    return $.extend({}, defaults, item);
+  };
+
   SelectAdapter.prototype.matches = function (params, data) {
     var matcher = this.options.get('matcher');
 

+ 61 - 42
dist/js/select2.amd.js

@@ -1098,68 +1098,87 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var $option = $('<option></option>');
+    var option = document.createElement('option');
 
-    $option.text(data.text);
-    $option.val(data.id);
-    $option.prop('disabled', data.disabled || false);
-    $option.prop('selected', data.selected || false);
+    option.value = data.id;
 
-    // Get any automatically generated data values
-    var detectedData = this.item($option);
+    if (data.disabled) {
+      option.disabled = true;
+    }
+
+    if (data.selected) {
+      option.selected = true;
+    }
 
-    // Merge it with the already present data
-    var combinedData = $.extend({}, data, detectedData);
+    option.innerText = data.text;
+
+    var $option = $(option);
+
+    var normalizedData = this._normalizeItem(data);
 
     // Override the option's data with the combined data
-    $option.data('data', combinedData);
+    $.data($option, normalizedData);
 
     return $option;
   };
 
   SelectAdapter.prototype.item = function ($option) {
-    var data = $option.data('data');
-
-    // If the data has already be generated, use it
-    if (data == null) {
-      if ($option.is('option')) {
-        data = {
-          id: $option.val(),
-          text: $option.html(),
-          disabled: $option.prop('disabled')
-        };
-      } else if ($option.is('optgroup')) {
-        data = {
-          text: $option.attr('label'),
-          children: []
-        };
-
-        var $children = $option.children('option');
-        var children = [];
-
-        for (var c = 0; c < $children.length; c++) {
-          var $child = $($children[c]);
-
-          var child = this.item($child);
-
-          children.push(child);
-        }
+    var data = {};
 
-        data.children = children;
-      }
+    if ($.hasData($option)) {
+      data = $option.data('data');
 
-      if (data.id && this.container != null) {
-        data._resultId = this.generateResultId(this.container, data);
+      if (data != null) {
+        return data;
       }
+    }
+
+    if ($option.is('option')) {
+      data = {
+        id: $option.val(),
+        text: $option.html(),
+        disabled: $option.prop('disabled')
+      };
+    } else if ($option.is('optgroup')) {
+      data = {
+        text: $option.attr('label'),
+        children: []
+      };
+
+      var $children = $option.children('option');
+      var children = [];
 
-      data.selected = $option.prop('selected');
+      for (var c = 0; c < $children.length; c++) {
+        var $child = $($children[c]);
 
-      $option.data('data', data);
+        var child = this.item($child);
+
+        children.push(child);
+      }
+
+      data.children = children;
     }
 
+    data = this._normalizeItem(data);
+
+    $option.data('data', data);
+
     return data;
   };
 
+  SelectAdapter.prototype._normalizeItem = function (item) {
+    var defaults = {
+      selected: false,
+      disabled: false
+    };
+
+    if (item._resultId == null && item.id && this.container != null) {
+      item._resultId = this.generateResultId(this.container, item);
+    }
+
+    return $.extend({}, defaults, item);
+  };
+
   SelectAdapter.prototype.matches = function (params, data) {
     var matcher = this.options.get('matcher');
 

+ 58 - 39
dist/js/select2.full.js

@@ -10633,68 +10633,87 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var $option = $('<option></option>');
+    var option = document.createElement('option');
 
-    $option.text(data.text);
-    $option.val(data.id);
-    $option.prop('disabled', data.disabled || false);
-    $option.prop('selected', data.selected || false);
+    option.value = data.id;
 
-    // Get any automatically generated data values
-    var detectedData = this.item($option);
+    if (data.disabled) {
+      option.disabled = true;
+    }
+
+    if (data.selected) {
+      option.selected = true;
+    }
 
-    // Merge it with the already present data
-    var combinedData = $.extend({}, data, detectedData);
+    option.innerText = data.text;
+
+    var $option = $(option);
+
+    var normalizedData = this._normalizeItem(data);
 
     // Override the option's data with the combined data
-    $option.data('data', combinedData);
+    $.data($option, normalizedData);
 
     return $option;
   };
 
   SelectAdapter.prototype.item = function ($option) {
-    var data = $option.data('data');
-
-    // If the data has already be generated, use it
-    if (data == null) {
-      if ($option.is('option')) {
-        data = {
-          id: $option.val(),
-          text: $option.html(),
-          disabled: $option.prop('disabled')
-        };
-      } else if ($option.is('optgroup')) {
-        data = {
-          text: $option.attr('label'),
-          children: []
-        };
+    var data = {};
+
+    if ($.hasData($option)) {
+      data = $option.data('data');
+
+      if (data != null) {
+        return data;
+      }
+    }
 
-        var $children = $option.children('option');
-        var children = [];
+    if ($option.is('option')) {
+      data = {
+        id: $option.val(),
+        text: $option.html(),
+        disabled: $option.prop('disabled')
+      };
+    } else if ($option.is('optgroup')) {
+      data = {
+        text: $option.attr('label'),
+        children: []
+      };
 
-        for (var c = 0; c < $children.length; c++) {
-          var $child = $($children[c]);
+      var $children = $option.children('option');
+      var children = [];
 
-          var child = this.item($child);
+      for (var c = 0; c < $children.length; c++) {
+        var $child = $($children[c]);
 
-          children.push(child);
-        }
+        var child = this.item($child);
 
-        data.children = children;
+        children.push(child);
       }
 
-      if (data.id && this.container != null) {
-        data._resultId = this.generateResultId(this.container, data);
-      }
+      data.children = children;
+    }
 
-      data.selected = $option.prop('selected');
+    data = this._normalizeItem(data);
 
-      $option.data('data', data);
-    }
+    $option.data('data', data);
 
     return data;
   };
 
+  SelectAdapter.prototype._normalizeItem = function (item) {
+    var defaults = {
+      selected: false,
+      disabled: false
+    };
+
+    if (item._resultId == null && item.id && this.container != null) {
+      item._resultId = this.generateResultId(this.container, item);
+    }
+
+    return $.extend({}, defaults, item);
+  };
+
   SelectAdapter.prototype.matches = function (params, data) {
     var matcher = this.options.get('matcher');
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/js/select2.full.min.js


+ 58 - 39
dist/js/select2.js

@@ -1526,68 +1526,87 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var $option = $('<option></option>');
+    var option = document.createElement('option');
 
-    $option.text(data.text);
-    $option.val(data.id);
-    $option.prop('disabled', data.disabled || false);
-    $option.prop('selected', data.selected || false);
+    option.value = data.id;
 
-    // Get any automatically generated data values
-    var detectedData = this.item($option);
+    if (data.disabled) {
+      option.disabled = true;
+    }
+
+    if (data.selected) {
+      option.selected = true;
+    }
 
-    // Merge it with the already present data
-    var combinedData = $.extend({}, data, detectedData);
+    option.innerText = data.text;
+
+    var $option = $(option);
+
+    var normalizedData = this._normalizeItem(data);
 
     // Override the option's data with the combined data
-    $option.data('data', combinedData);
+    $.data($option, normalizedData);
 
     return $option;
   };
 
   SelectAdapter.prototype.item = function ($option) {
-    var data = $option.data('data');
-
-    // If the data has already be generated, use it
-    if (data == null) {
-      if ($option.is('option')) {
-        data = {
-          id: $option.val(),
-          text: $option.html(),
-          disabled: $option.prop('disabled')
-        };
-      } else if ($option.is('optgroup')) {
-        data = {
-          text: $option.attr('label'),
-          children: []
-        };
+    var data = {};
 
-        var $children = $option.children('option');
-        var children = [];
+    if ($.hasData($option)) {
+      data = $option.data('data');
 
-        for (var c = 0; c < $children.length; c++) {
-          var $child = $($children[c]);
+      if (data != null) {
+        return data;
+      }
+    }
 
-          var child = this.item($child);
+    if ($option.is('option')) {
+      data = {
+        id: $option.val(),
+        text: $option.html(),
+        disabled: $option.prop('disabled')
+      };
+    } else if ($option.is('optgroup')) {
+      data = {
+        text: $option.attr('label'),
+        children: []
+      };
 
-          children.push(child);
-        }
+      var $children = $option.children('option');
+      var children = [];
 
-        data.children = children;
-      }
+      for (var c = 0; c < $children.length; c++) {
+        var $child = $($children[c]);
 
-      if (data.id && this.container != null) {
-        data._resultId = this.generateResultId(this.container, data);
-      }
+        var child = this.item($child);
 
-      data.selected = $option.prop('selected');
+        children.push(child);
+      }
 
-      $option.data('data', data);
+      data.children = children;
     }
 
+    data = this._normalizeItem(data);
+
+    $option.data('data', data);
+
     return data;
   };
 
+  SelectAdapter.prototype._normalizeItem = function (item) {
+    var defaults = {
+      selected: false,
+      disabled: false
+    };
+
+    if (item._resultId == null && item.id && this.container != null) {
+      item._resultId = this.generateResultId(this.container, item);
+    }
+
+    return $.extend({}, defaults, item);
+  };
+
   SelectAdapter.prototype.matches = function (params, data) {
     var matcher = this.options.get('matcher');
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/js/select2.min.js


+ 61 - 42
src/js/select2/data/select.js

@@ -121,68 +121,87 @@ define([
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var $option = $('<option></option>');
+    var option = document.createElement('option');
 
-    $option.text(data.text);
-    $option.val(data.id);
-    $option.prop('disabled', data.disabled || false);
-    $option.prop('selected', data.selected || false);
+    option.value = data.id;
 
-    // Get any automatically generated data values
-    var detectedData = this.item($option);
+    if (data.disabled) {
+      option.disabled = true;
+    }
+
+    if (data.selected) {
+      option.selected = true;
+    }
+
+    option.innerText = data.text;
+
+    var $option = $(option);
 
-    // Merge it with the already present data
-    var combinedData = $.extend({}, data, detectedData);
+    var normalizedData = this._normalizeItem(data);
 
     // Override the option's data with the combined data
-    $option.data('data', combinedData);
+    $.data($option, normalizedData);
 
     return $option;
   };
 
   SelectAdapter.prototype.item = function ($option) {
-    var data = $option.data('data');
-
-    // If the data has already be generated, use it
-    if (data == null) {
-      if ($option.is('option')) {
-        data = {
-          id: $option.val(),
-          text: $option.html(),
-          disabled: $option.prop('disabled')
-        };
-      } else if ($option.is('optgroup')) {
-        data = {
-          text: $option.attr('label'),
-          children: []
-        };
-
-        var $children = $option.children('option');
-        var children = [];
-
-        for (var c = 0; c < $children.length; c++) {
-          var $child = $($children[c]);
-
-          var child = this.item($child);
-
-          children.push(child);
-        }
+    var data = {};
 
-        data.children = children;
-      }
+    if ($.hasData($option)) {
+      data = $option.data('data');
 
-      if (data.id && this.container != null) {
-        data._resultId = this.generateResultId(this.container, data);
+      if (data != null) {
+        return data;
       }
+    }
+
+    if ($option.is('option')) {
+      data = {
+        id: $option.val(),
+        text: $option.html(),
+        disabled: $option.prop('disabled')
+      };
+    } else if ($option.is('optgroup')) {
+      data = {
+        text: $option.attr('label'),
+        children: []
+      };
+
+      var $children = $option.children('option');
+      var children = [];
 
-      data.selected = $option.prop('selected');
+      for (var c = 0; c < $children.length; c++) {
+        var $child = $($children[c]);
 
-      $option.data('data', data);
+        var child = this.item($child);
+
+        children.push(child);
+      }
+
+      data.children = children;
     }
 
+    data = this._normalizeItem(data);
+
+    $option.data('data', data);
+
     return data;
   };
 
+  SelectAdapter.prototype._normalizeItem = function (item) {
+    var defaults = {
+      selected: false,
+      disabled: false
+    };
+
+    if (item._resultId == null && item.id && this.container != null) {
+      item._resultId = this.generateResultId(this.container, item);
+    }
+
+    return $.extend({}, defaults, item);
+  };
+
   SelectAdapter.prototype.matches = function (params, data) {
     var matcher = this.options.get('matcher');
 

+ 17 - 6
tests/data/select-tests.js

@@ -238,13 +238,24 @@ test('empty optgroups are still shown when queried', function (assert) {
   var data = new SelectData($select, options);
 
   data.query({}, function (data) {
-    assert.deepEqual(
-      data[1],
-      {
-        text: 'Empty',
-        children: []
-      },
+    assert.equal(
+      data.length,
+      2,
       'The empty optgroup element should still be returned when queried'
     );
+
+    var item = data[1];
+
+    assert.equal(
+      item.text,
+      'Empty',
+      'The text of the empty optgroup should match the label'
+    );
+
+    assert.equal(
+      item.children.length,
+      0,
+      'There should be no children in the empty opgroup'
+    );
   });
 });

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.