Select2 is slow on opening #781

Closed
MgSam opened this Issue Jan 31, 2013 · 80 comments

Comments

Projects
None yet

MgSam commented Jan 31, 2013

I'm finding Select2 is quite slow when opening its dropdown menu if the underlying select has a fair number of items. Am I right in guessing it is (re)creating the HTML/DOM for this dropdown each time it is invoked? Wouldn't it make more sense to cache this and only redraw it if the underlying select changes?

Here's an example:
http://jsfiddle.net/48wFG/1/

Thanks in advance.

Contributor

ivaynberg commented Jan 31, 2013

you are right in your analysis.

its not possible to cache the dom because searching using the search field mangles it. instead, the default query function used when attached to selects should implement partial loading with infinite scrolling - just like server side though, albeit with a bigger page size.

will try to look into it when i have time.

kevin-brown referenced this issue Feb 1, 2013

Closed

IE8 Slow #787

DR9885 commented Feb 4, 2013

After taking a closer look at the code, I noticed a couple things causing these large performance hits on IE.

  1. Inside the "populateResults" method, DOM Manipluation is being done with the jQuery Library, which is great for readability, but poor for performance.

REF: http://www.artzstudio.com/2009/04/jquery-performance-rules/#limit-dom-manipulation

  1. There is never any caching, even if the select never changes (Unless I'm not aware of some setting to achieve this).

sandrods commented Mar 1, 2013

+1

ximi commented Mar 4, 2013

+1

gazMac2 commented Mar 5, 2013

@DR9885 Looks like you are correct with this. I did some tests and there was some real speed improvements doing that. However, I can't get that function to work quite right. Did you ever implement the changes in this function and would you share your code?

MgSam commented Mar 5, 2013

I agree that the list creation code should be rewritten to make the complete HTML in string form and then do a single JQuery call to make the actual DOM elements.

DR9885 commented Mar 5, 2013

@gazMac2 I did spend some time with the code to make changes, but it looked more than just a quick change and sadly I don't have too much time available.

Also it does look like the plugin rebuilds the ENTIRE list anytime a user opens or filters. I wonder if we could cache some of the html & results, or even better maybe inject a Template Engine.

vtt commented Apr 1, 2013

+1

bostondp commented May 2, 2013

+1

ova2 commented May 11, 2013

@DR9885 Great analysis. +1 for 1) and 2).

Hi,

I am having exactly the same issue here which is even more severe on IE.

Is there any update on this? Are there any plan to fix this in a short term?

Thanks

Contributor

ivaynberg commented Jun 7, 2013

short term you can write your own query function that retrieves options piecemeal.

MgSam commented Jun 18, 2013

Speaking of performance issues- I was looking through the source and I noticed it filters out duplicates by using an indexOf() function that searches for a matching entry through the array of entries. This is O(n^2) and really should be rewritten to use a hashtable instead.

        updateSelection: function (data) {
            var ids = [], filtered = [], self = this;

            // filter out duplicates
            $(data).each(function () {
                if (indexOf(self.id(this), ids) < 0) {
                    ids.push(self.id(this));
                    filtered.push(this);
                }
            });
            data = filtered;

            this.selection.find(".select2-search-choice").remove();
            $(data).each(function () {
                self.addSelectedChoice(this);
            });
            self.postprocessResults();
        }

There are a few other places indexOf() is used while looping through the list as well.

ova2 commented Jun 18, 2013

Also jQuery each is slower than a native loop. It is better to use a native loop.

var $data = $(data);
var length = $data.length;
for (var i=0; i < length; i++) {
   // access with. $data[i]
   ...
});

Almost every tutorial suggest to avoid each and push. push is slow too. So, this code (adding of a new element can be in a loop of course)

var myArray = [];
var newElement = "test element";
myArray[myArray.length] = newElement;

works faster than this one

var myArray = new Array();
var newElement = "test element";
myArray.push(newElement);
Contributor

ivaynberg commented Jun 18, 2013

@MgSam @ova2 pull requests are welcome

+1

efib commented Aug 8, 2013

+1

kanfet commented Aug 13, 2013

+1

Contributor

jdecuyper commented Aug 16, 2013

@ivaynberg: beside fixing the indexOf performance issue with a hashtable or similar, would it be a a good idea to use the each2 implementation for the iteration?

Contributor

ivaynberg commented Aug 16, 2013

probably, but i dont think it will help much. what should really happen is that the rendering should be done in a string and then bound with data later. this is how it worked originally, but i made the mistake of refactoring it to make renderers more flexible. in 4.0 i will go back.

czj commented Aug 16, 2013

Thanks a lot @ivaynberg that will be great :-)

+1

eeng commented Oct 1, 2013

+1

+1. Not just an IE issue,a nd not limited to large lists Noticeable on Chrome on Mac, even with 3 options.

Actually, on further investigation, list size is only part of the issue. The size of the page/DOM tree seems to affect it considerably.

I'm using select2 in a form filter. With a a table of 40 rows below the form, the dropdowns are slow to respond. Worse, the whole page scrolls slowly. With no table on the page, the dropdowns are much quicker.

Owner

kevin-brown commented Oct 17, 2013

@howieweiner Can you create a jsfiddle or something to reproduce that part of the issue?

Here you go:
http://jsfiddle.net/howieweiner/hyXUh/12/

Issue can be seen on full screen fiddle:
http://jsfiddle.net/howieweiner/hyXUh/12/embedded/result/

Think it might be related to bootstrap. Really odd. On a large/wide screen it's slow. Reducing screen size removes the delay. Removing the table data does too.

abraxxa commented Oct 21, 2013

+1

+1

Rolling back to 2.x release has improved performance for me.

tylik1 commented Oct 29, 2013

On firefox 24 script v2.x is also rather slow even with 1000+ options

@vollnhals vollnhals added a commit to vollnhals/select2 that referenced this issue Nov 22, 2013

@vollnhals vollnhals replace most of jquery function calls with string concatenation in po…
…pulate()

This significantly speeds up the time populate takes on large datasets.

With 6000 entries the time goes from 980ms to 760ms. A performance increase of 22%.

Also see relevant discussion in #781
19684e3

Timshel commented Dec 12, 2013

Made a fiddle of using partial loading with infinite scrolling :
http://jsfiddle.net/Z7bDG/1/

mselley commented Dec 19, 2013

On selecting a large amount of data on load. I found it was doing the setVal() for every item. Checking for duplicated each time.
If i added 3000 items it was checking the list of 3000 3000 times!

Which would make it take well forever to render the box.

I replaced the setVal function with this:

    setVal: function (val) {
        if (this.select) {
            this.select.val(val);
        } else {

            //filter out duplicates
            var distinct = [];
            var unique = {};
            for (var i in val) {

                if (typeof (unique[val[i]]) == "undefined") {
                    distinct.push(val[i]);
                }
                unique[val[i]] = 0;
            }

            this.opts.element.val(distinct.length === 0 ? "" : distinct.join(this.opts.separator));
        }
    },

Which seems to give me a performance increase of around 100x.

This fixes the performance of checking for duplicates. But i don't think it should be running this check for every item on initial load. Just once at the end of the initial val setup.

mselley commented Dec 19, 2013

I had a look further and found that in

    // multi
    updateSelection: function (data) {

it is calling

        $(data).each(function () {
            self.addSelectedChoice(this);
        });

and in addSelectedChoice it has

this.setVal(val);

so setVal will get called once for every item selected on load.

I have put in a fix that adds isBulk to "addSelectedChoice"

code as follows:

    addSelectedChoice: function (data, isBulk) {
        var enableChoice = !data.locked,
            enabledItem = $(
                "<li class='select2-search-choice'>" +
                "    <div></div>" +
                "    <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" +
                "</li>"),
            disabledItem = $(
                "<li class='select2-search-choice select2-locked'>" +
                "<div></div>" +
                "</li>");
        var choice = enableChoice ? enabledItem : disabledItem,
            id = this.id(data),
            val = this.getVal(),
            formatted,
            cssClass;

        formatted = this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
        if (formatted != undefined) {
            choice.find("div").replaceWith("<div>" + formatted + "</div>");
        }
        cssClass = this.opts.formatSelectionCssClass(data, choice.find("div"));
        if (cssClass != undefined) {
            choice.addClass(cssClass);
        }

        if (enableChoice) {
            choice.find(".select2-search-choice-close")
                .on("mousedown", killEvent)
                .on("click dblclick", this.bind(function (e) {
                    if (!this.isInterfaceEnabled()) return;

                    $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function () {
                        this.unselect($(e.target));
                        this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
                        this.close();
                        this.focusSearch();
                    })).dequeue();
                    killEvent(e);
                })).on("focus", this.bind(function () {
                    if (!this.isInterfaceEnabled()) return;
                    this.container.addClass("select2-container-active");
                    this.dropdown.addClass("select2-drop-active");
                }));
        }

        choice.data("select2-data", data);
        choice.insertBefore(this.searchContainer);

        val.push(id);

        if (isBulk != true) {
            this.setVal(val);
        }
    },

Then in updateSelection you need to call the setVal after the loop so it becomes:

    updateSelection: function (data) {
        var ids = [], filtered = [], self = this;

        // filter out duplicates
        $(data).each(function () {
            if (indexOf(self.id(this), ids) < 0) {
                ids.push(self.id(this));
                filtered.push(this);
            }
        });
        data = filtered;

        this.selection.find(".select2-search-choice").remove();
        $(data).each(function () {
            self.addSelectedChoice(this,true);
        });
        this.setVal(ids);
        self.postprocessResults();
    },

This gives me a huge performance improvement. The speed increase stops the exponential slowdown!

wgorski commented Dec 19, 2013

+1

djevrek commented Dec 30, 2013

+1

Contributor

jdecuyper commented Jan 31, 2014

@ivaynberg: I tried PR #1926 and it helps reduce the loading time a bit. Is this how it used to work before the refactoring?

For those struggling with speed issues, the best option (as of now) is to write your own query function as explained in this jsfiddle.

uaoleg referenced this issue in uaoleg/icpc.org.ua Mar 3, 2014

Closed

Signup: school list lags #166

Contributor

ycdtosa commented Mar 7, 2014

Wow. This one did bite me by surprise, and the jsfiddle provided where very handy, thanks a lot.

Here yet another jsfiddle with Diacritics support using query to load fast while matching 'tac' with 'tác'; a requirement i had.

(forked from @Timshel previous jsfiddle.)

UPDATE: added cache of the stripped_Diacritics data (good big/huge lists).

radsaq commented Mar 12, 2014

@mselley Feel like opening a pull request with your changes? If you don't, I will.

mselley commented Mar 12, 2014

@radsaq I will have a look at my changes and do a pull asap.

@mselley mselley added a commit to mselley/select2 that referenced this issue Mar 12, 2014

@mselley mselley Fix issue #781 1e621f7

mselley referenced this issue Mar 13, 2014

Closed

Fix issue #781 #2186

@Timshel, your code is working as expected. Thank you for sharing.

People, take a look at http://jsfiddle.net/Z7bDG/1/.

jaygen commented Mar 14, 2014

@mselley Thank you! 👍

Hello, I'm also having some strange performance issues, I hope someone here could give some advice.

  1. I'm using jQuery 1.11.0.
  2. I'm attaching the select2 component to a "select" element.
  3. I've added 100 test options with unique values (1...100).
  4. I tried to turn on and off the search feature, but turned out it doesn't matter.

With these circumstances, and with the lastest github download, opening my select takes nearly 2-3 seconds...

I've checked the same scenario with the 2.1 release, and opening the select was nearly instantious.

If anyone has an idea what could cause this and which workaround I could apply, please help.

I started my own digging, so I've checked the fork with the rewrite of the populate method to use string concatenation, but it didn't have too much effect for me. Then I debuged that the really slow performance comes with the container.append(node) call.

I replaced it with concatenating the created "li" nodes into a long html string, and after the loop I called the container.html(myLongNodesString) method. This way I got instantious options popup with the current version as well.

abraxxa commented Mar 17, 2014

Makes sense as DOM manipulation triggers a html reflow.

lahwran commented Mar 21, 2014

@cervengoc would you mind sharing your changes?

Contributor

ycdtosa commented Mar 28, 2014

Hi. After some profiling on my side and trying to isolate some of the performance problems with a huge list, I saw stripDiacritics getting a lot of processor time. It is just one of the problems, and not the biggest, but worth taking a look at it.

Some googleing got me here: http://stackoverflow.com/q/990904/359284, and then here http://jsperf.com/diacritics/12

The "what?" removeDiacritics function is doing the same job as stripDiacritics at select2 but faster.

I just added to the test the select2 stripDiacritics as "loop" on http://jsperf.com/diacritics/13, and it is reported 87% slower than "what?" ( using chrome )

The code has three parts.
1.- The more or less readable diacritics table.
2.- A loop to generate "diacriticsMap", (just like DIACRITICS array).
3.- the removeDiacritics. (just our stripDiacritics).

So I just got those into a branch for anyone willing to test it. ( caveat: i'm new here at the hub, so not to sure of what i did )

Even if the map generates a bigger DIACRITICS array, the array has the same layout,
Only the new stripDiacritics is needed, i'm positive the could keep the current DIACRITICS
array as it is now, however the generated "diacriticsMap" seems to be more complete.

aorielly commented Apr 3, 2014

+1

@kevin-brown kevin-brown modified the milestone: 3.4.7, 4.0 Apr 16, 2014

dovy commented Apr 26, 2014

+1

Hello, sorry I had no time until now. Here is the code I've changed, and for me it caused dramatic performance improvement. First I reverted to string concatenation instead of jQuery for most of the construction of the item nodes. Than I applied a bulk append for all new nodes instead of one by one (this had the biggest effect at me).

populate=function(results, container, depth) {
     var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted, formattedClass;

     results = opts.sortResults(results, container, query);

     // collect the created nodes for bulk append
     var nodes = [];
     for (i = 0, l = results.length; i < l; i = i + 1) {
           result=results[i];
           disabled = (result.disabled === true);
           selectable = (!disabled) && (id(result) !== undefined);
           compound=result.children && result.children.length > 0;

           node = "<li class=\"";
           node += "select2-results-dept-" + depth;
           node += " select2-result";
           node += selectable ? " select2-result-selectable" : " select2-result-unselectable";
           if (disabled)
                  node += " select2-disabled";
           if (compound)
                  node += " select2-result-with-children";
           formattedClass = self.opts.formatResultCssClass(result);
           if (formattedClass != undefined)
                  node += " " + formattedClass;
           node += "\" role=\"presentation\">";

           label = "<div class=\"select2-result-label\"";
           label += " id=\"select2-result-label-" + nextUid() + "\"";
           label += " role=\"option\"";
           label += ">";
           formatted = opts.formatResult(result, label, query, self.opts.escapeMarkup);
           if (formatted !== undefined)
                 label += formatted;
           label += "</div>";

           node += label;
           node += "</li>";

           // I still used jQuery wrapping for setting "data" below
           node = $(node);

           if (compound) {
                  innerContainer=$("<ul></ul>");
                  innerContainer.addClass("select2-result-sub");
                  populate(result.children, innerContainer, depth+1);
                  node.append(innerContainer);
           }

           node.data("select2-data", result);
           nodes.push(node[0]);
     }

     // bulk append the created nodes
      container.append(nodes);

      liveRegion.text(opts.formatMatches(results.length));
};

@cervengoc , did your change give a dramatic improvement AFTER commit 7c9c961?
I thought that commit had largely solved the speed issue?

@dfrencham Sorry I have no idea currently, my changes were made a while ago and didn't have time since then to try the latest versions. Only thing I know is that the latest version also has the one-by-one DOM insertion instead of the batch version, and I'm quite sure that this change can only improve things (doesn't seem to be dangerous for introducing any bugs), so why not anyway. :)

I will try the latest code today though.

I've checked my version, and it turned out that I applied my changes before that specific commit. However, I apploeid the changes from that commit as well, and I experienced that those alone (with reverting my changes) didn't have too much effect at me. So I guess my changes can still improve performance even further.

Contributor

ycdtosa commented May 10, 2014

@cervengoc Those changes do improve performance on the stripDiacritics function, and there is a big measurable improvement whith the new code. However, with BIG datasets, it still a lot
of work to do, specially if you are not using the "query" function, and just use the "data" function.

This is so because select2 applies the function to all the unmatched data you dataset, and when you type the first char, that is ALL you HUGE dataset, and that is heavy load even without stripDiacritics involved.

The best way to overcome this involves:

A) The key part is to use the query function, It will stop once you matched X items for the user to view on the dropdown. Whatever is left out will be computed when he types or scrolls down, This is the key. The user will get its data MUCH faster.

B) When you call stripDiacritics (or compute any other value from every item in your data)
save a cached value at you dataset if you can, so you don't have to compute it again.

I did write http://jsfiddle.net/uLqc9/4/ before commit 7c9c961, and still serves its purpose.
And there are other jsfiddles around with 'query' implementations.

Still the key part is A)

@ycdtosa, thank you for the additional guidelines and clarifications. I have read some bits of your point in the earlier part of this thread, but it wasn't entirely applicable to my scenario. I had:

  • I didn't have search input enabled.
  • I had about 60 static options (from select tag) with short (4-5 chars) texts without diacritics.

In this scenario my modifications implied the biggest performance improvement, because the bottleneck was that each time the select opened, all the 60 options were reparsed and recreated their select2 elements. However, I've tested it only in FF 28, probably other browsers behave differently. I still think my changes could be implemented, because as far as my knowledge it doesn't change any logic and does the same task more efficiently.

kevin-brown reopened this May 10, 2014

Owner

kevin-brown commented May 10, 2014

This is likely going to be a long-running issue, as the plugin can always load data faster.

I'm open to another pull request being made, but care needs to be taken to ensure that backwards compatibility will be maintained along the way.

Contributor

ycdtosa commented May 11, 2014

@cervengoc. Yeap. I see your point. Your code addresses a different problem.
In fact I see these as even a different issue, To keep up with the list I started before...

A) rendering all the options ( fix/workaround available: using "query" )
B) stripDiacritics is slow ( already fixed )
C) populate is slow due to DOM manipulation ( string manipulation seems faster )

I'll be testing your code tomorrow, as it makes sense and it does address the most
widely used code. ( improvement should affect those using "data" and/or those "query" regardless of
the use of stripDiacriptics. )

@kevin-brown kevin-brown modified the milestone: 3.5.0, 3.4.8 May 12, 2014

Contributor

ycdtosa commented May 12, 2014

@cervengoc. That code gives me an average 45% speed boost in the updateResults / populateResults code as measured with latest chrome. Sample running with a 10000 items list and "data" (vs "query").

Other browsers will get different results.

Since the function populate is called in a loop and recursively big sets of data will be affected for the better.

@ycdtosa ycdtosa added a commit to ycdtosa/select2 that referenced this issue May 12, 2014

@ycdtosa ycdtosa changes on updateResults, populate by @cervengoc on #781
use string concatenation instead of DOM manipulation at populate. This
does gives about a 45% speed boost as measured with chrome v35. Code by
@cervengoc on #781
12e0de2

MgSam's comment also describes my issue. My data set is relatively small (100-500) but I am initializing a lot of select2 controls (each is in multiple select mode). In this use case there are items which need to be programatically selected upon initialization. I am using version 3.4.8 and the bottleneck is in the reliance of the indexOf function. This module would benefit from an order of magnitude improvement if an associative array was used for comparisons. In this specific case (see code snippet below) maintaining a sorted collection and using binary searches may be a good local fix because the data scope is limited to this method (in general special care is needed for international character set comparisons...this may benefit from the stripDiacritics modification made in 7c9c961).

The following code snippet is hogging all the CPU and it is because of its reliance on indexOf.

        // multi
        setVal: function (val) {
            var unique;
            if (this.select) {
                this.select.val(val);
            } else {
                unique = [];
                // filter out duplicates
                $(val).each(function () {
                    if (indexOf(this, unique) < 0) unique.push(this);
                });
                this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
            }
        },

Are any of the maintainers invested in this issue or willing to introduce appropriate datatypes?

@ycdtosa ycdtosa added a commit to ycdtosa/select2 that referenced this issue May 13, 2014

@ycdtosa ycdtosa Revert "changes on updateResults, populate by @cervengoc on #781"
This reverts commit 12e0de2.
c14f45c
Contributor

ycdtosa commented May 13, 2014

Anyone willing to run http://jsperf.com/documentfragment-appendchild-vs-jquery-append/49 ?
(testing just the bulk insertion as in the populate function )
That code is testing a loop and bulk insertion of nodes, it would be nice to have some stats on it.
The build code from @cervengoc is tested there, and i will be doing a pull request with it soon.

I made some modifications just to get past the setVal() bottleneck to further diagnose the performance bottlenecks for my usecase. These modifications do not take into account any of the comparison functions for special character sets nor does it use the equals() method provided by the select2 module. This was done to isolate the next bottleneck which appears to be the clearSearch() method (see image below). The line numbers should match (or be close enough to) version 3.4.8 with the modification made in the below patch.

image

The getMaxSearchWidth() call in clearSearch() appears to be the next bottleneck and just so happens for my purposes I was able to defer this call until the value was needed inside the if block. I will include the patch, but I don't think it will be usable in its current form as there was no attempt to make the solution generic with respect to international characters (or using the equals() comparator). It may be a useful temporary hack if your use case does not require support for these features.

--- ~/Downloads/select2-3.4.8/select2.js    2014-05-01 09:50:38.000000000 -0400
+++ ./src/main/webapp/resources/js/jquery.select2.js    2014-05-13 10:29:34.000000000 -0400
@@ -2822,13 +2822,13 @@

         // multi
         clearSearch: function () {
-            var placeholder = this.getPlaceholder(),
-                maxWidth = this.getMaxSearchWidth();
+            var placeholder = this.getPlaceholder();

             if (placeholder !== undefined  && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
                 this.search.val(placeholder).addClass("select2-default");
                 // stretch the search box to full width of the container so as much of the placeholder is visible as possible
                 // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
+                var maxWidth = this.getMaxSearchWidth();
                 this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
             } else {
                 this.search.val("").width(10);
@@ -3160,9 +3160,13 @@
                 this.select.val(val);
             } else {
                 unique = [];
+                var indexMap = {};
                 // filter out duplicates
                 $(val).each(function () {
-                    if (indexOf(this, unique) < 0) unique.push(this);
+                    if (!(this in indexMap)) {
+                       indexMap[this] = unique.length;
+                       unique.push(this);
+                    }
                 });
                 this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
             }

I have also tried the populate method submitted by @cervengoc. I see around %30-10 performance improvement with ~2000 plain text items. This is and improvement but I agree with others that there are a few other general design and data-structure changes that also would provide performance improvements. In the current state selecting 1 item (in multi-select mode) results in a re-build of the entire structure which can take over a second (of which the UI is frozen) with just ~2000 plain text items.

I don't think using AJAX for ~2000 text items is a scalable approach, assuming many users are active at any given time. Shipping this information to the client is quick and can be efficiently compressed, and the server need not be bogged down by every search/filter operation (especially if the same data is going to be used for multiple select controls). Rolling a custom caching scheme is an alternative but if this is the solution then I think developers will just create their own plugins (or use another plugin) that don't have the same limitations.

It seems as though the caching scheme and brute force look-ups (indexOf) would be a good initial focal point.
@ivaynberg - "its not possible to cache the dom because searching using the search field mangles it"...Is it possible to decouple data from display? Is it necessary to rely on the DOM to do lookups through the data? The select2 data interface already requires that an id be specified, how can this be used for associative array indexing? If it cannot be used as an index there should be some thought invested in an alternative way to build/maintain an associative array for searching/indexing.

Check out selectize.js as an alternative or reference for redesign.

styfle commented May 14, 2014

@ycdtosa Wow this is great! http://jsfiddle.net/uLqc9/4/
The lazy loading used in this example basically solves my problem of slow open and slow search.
The only disadvantage is that the selected item is not highlighted upon opening the dropdown if that item is not on the first page.

I suppose you could figure out what page the selected item is on and only load that page upon opening the dropdown and provide scroll up and down lazy loading. That would be the killer solution.

Great work!

@kevin-brown kevin-brown added a commit that referenced this issue May 27, 2014

@kevin-brown kevin-brown Merge pull request #2360 from ycdtosa/master
changes on updateResults, populate by @cervengoc on #781
d487fc5

kevin-brown removed this from the 3.5.0 milestone Jun 4, 2014

I think related to this issue, I'm currently trying to load a large table (8800 Rows / 2.5mib) however it crashes. In Chrome F12 I get an error of:

POST http://localhost/web/app_dev.php/_entity_find 500 (Internal Server Error) main.js:3
k.cors.a.crossDomain.send main.js:3
n.extend.ajax main.js:3
(anonymous function)

(main.js is my compiled JS containing select2)

I have other select2 autocomplete fields on the same page searching smaller tables which work perfectly fine (a little slow but nothing major)

Looking in apache error.log I have this error:

[client ::1:55760] AH00124: Request exceeded the limit of 10 internal redirects due to probable     configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel     debug' to get a backtrace., referer: http://localhost/web/app_dev.php/user/prod/new

If I load the field as a plain choice field It loads fine, rather large and take around 7 seconds but loads all the same.

Using Symfony 2.4.* , Doctrine2 and the most up to date download of select2.

Turns out my problem was solved by re building the table with a new id column and scraping the old one don't understand why but it solved it.

kevin-brown removed the annoyance label Aug 22, 2014

Owner

kevin-brown commented Dec 11, 2014

At this point Select2 should handle much better on large amounts of data.

ivaynberg#2848 just got merged in for Select2 3.5.3, which should improve the speed considerably.

Select2 4.0 had a major focus on fixing the jQuery performance issues (which I will write a post about at some point). ivaynberg#2743

If there are still any major bottlenecks in either version, reply back to this with a jsfiddle and the version number and we can continue making improvements. Until then, I think this is at a point where it can be closed.

rikkert commented Dec 12, 2014

Great, thanks for letting us know.

On 11 dec. 2014, at 20:59, Kevin Brown notifications@github.com wrote:

Closed #781.


Reply to this email directly or view it on GitHub.

Still seeing a slowdown (4.0) on over even a thousand datasets (using templates for results, which i'm sure adds to overhead).

What about a user friendly loading view? As soon as the user clicks show the dropdown with a loading gif, then when the data loads replace said gif with the data?

If would support large amounts of data being a little sluggish without confusing the user as to if anything is actually happening or not.

So we can use this I'm about to add this functionality myself.

Owner

kevin-brown commented Jul 20, 2015

I'm a fan of the idea of displaying some sort of "loading" message when Select2 is processing the results, I'd even be willing to make it the default behaviour when Select2 is running slow.

If someone gets a pull request going for it, we can discuss the idea in more detail.

As soon as the user clicks show the dropdown with a loading gif, then when the data loads replace said gif with the data?

Right now we have a "Seaching..." string which we use for this (with AJAX, usually) that I wouldn't mind bringing to a standard <select> if possible.

We dropped the old spinner gif while removing external image dependencies from Select2, and I'd rather keep it out.

That sounds ideal, keeping the two UI experiences the same regardless of datasource. I'll look into that with my changes and make a pull request for it once I'm done for you to review.

Owner

fk commented Jul 22, 2015

Here's an issue tracking the missing loading image/spinner GIF: #3227 – I'll add my (incomplete) thoughts regarding the loading image over there.

I saw this jsfiddles (http://jsfiddle.net/uLqc9/4/) however I have problem with < select >. How to implement this lady load with < select > and >100 options. I have issue when trying to test by emulate IE<11 in IE Developer Tools. For IE 11 works fine

Sohorev commented Mar 2, 2016

Select2 slowly on 1000+ items
But chosen not slowly

Select 2, multiple, tag, two dropdowns - waiting time for opening a list of 40 items is 4-5 seconds (computer speed not a factor).

galeroy commented Feb 17, 2017 edited

It looks like upgrading to Select2 Version 3.5.3 improves speed for large lists.

What's not easy for me to find by looking around on the web:
What is the minimum version of AngularJS needed to support Select2 Version 3.5.3?

Thanks in advance if anyone knows this / where to find this info.

@v-evfila v-evfila pushed a commit to v-evfila/select2 that referenced this issue Mar 31, 2017

interestincode Update select2.js
As suggested in select2#781 (comment), significantly improves search speed, going from unusable to snappy on IE on a list of almost 10,000 items with a custom query limiting it to 25 results. Uses 'uni range + named function' from http://jsperf.com/diacritics/18
1920f9b

@v-evfila v-evfila pushed a commit to v-evfila/select2 that referenced this issue Mar 31, 2017

@kevin-brown kevin-brown Merge pull request #2286 from interestincode/patch-1
Update select2.js, fixes #781
46efe47

@v-evfila v-evfila pushed a commit to v-evfila/select2 that referenced this issue Mar 31, 2017

@ycdtosa ycdtosa changes on updateResults, populate by @cervengoc on #781
use string concatenation instead of DOM manipulation at populate. This
does gives about a 45% speed boost as measured with chrome v35. Code by
@cervengoc on #781
538341d

@v-evfila v-evfila pushed a commit to v-evfila/select2 that referenced this issue Mar 31, 2017

@ycdtosa ycdtosa Revert "changes on updateResults, populate by @cervengoc on #781"
This reverts commit 12e0de2.
b6e647f

@v-evfila v-evfila pushed a commit to v-evfila/select2 that referenced this issue Mar 31, 2017

@kevin-brown kevin-brown Merge pull request #2360 from ycdtosa/master
changes on updateResults, populate by @cervengoc on #781
72de0d9

SophiaAP referenced this issue in flask-admin/flask-admin Apr 10, 2017

Closed

select2 version bump? #1467

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment