Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Bad performance when selecting an item the first time in select with many items #8019

Closed
floydqwz opened this issue Jun 29, 2014 · 7 comments

Comments

@floydqwz
Copy link

When having many items in a (more than a couple of thousand items), selecting an item becomes really really slow the first time. In this example I add 25000 items. Selecting an item the first time takes around 12s. http://jsfiddle.net/2W7Kx/1/ Seems like "function render()" is responsible for almost all execution time, with these two lines being suspicious: // TODO(vojta): can't we optimize this ? scope.$watch(render); I also initially added a stackoverflow question about the issue: http://stackoverflow.com/questions/24470563/angularjs-performance-for-select

@caitp
Copy link
Contributor

caitp commented Jun 29, 2014

It takes a pretty stupidly long time with vanilla JS too: http://jsfiddle.net/P9mJQ/

I haven't looked at the numbers, so there might be marginal differences, but it actually feels pretty similar to the performance in AngularJS

@floydqwz
Copy link
Author

@caitp: I don't think that's a valid comparison. In my fiddle all the items can be shown quickly, but selecting one is what takes time. In your fiddle it's the creation of the option elements which take time.

@caitp
Copy link
Contributor

caitp commented Jun 29, 2014

not when I ran your reproduction --- creating the list takes a huge (and similar) amount of time in your fiddle, and selecting a new object is slightly faster in vanillaJS, but not by a whole lot.

I think you should probably avoid using these huge lists in your form controls anyways, it's a pretty terrible user interface when you get down to it

@btford
Copy link
Contributor

btford commented Jul 8, 2014

I agree with @caitp, but I'm curious if you have some specific use case for this, @floydqwz.

@btford btford added this to the Backlog milestone Jul 8, 2014
@floydqwz
Copy link
Author

floydqwz commented Jul 8, 2014

@btford: The use case is that I have a member database (2500 members). I want to select one of the members. Simple as that. Maybe there is a better way than using a since it seems a bit slow together with angular.

@g00fy-
Copy link

g00fy- commented Aug 12, 2014

Would it be possible to implement select in a way that would perform lazy rendering ?

By that I mean:

  1. render only selected/default value.
  2. on focus render the whole list, without using $apply

This would improve performance apps that have a large list of items like @floydqwz and most of the time the select input isn't even used (but is the bottleneck)

@petebacondarwin
Copy link
Contributor

#10639 improves this performance dramatically http://plnkr.co/edit/CBwddTL3WTwEVjAWCOQQ?p=preview

petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Jan 11, 2015
…ns are loaded async

**Major reworking of select and ngOptions**:

* The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives
to override to get their desired behaviour
* The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions`
directive could be deleted without having to make any changes to the `select` directive.
* Select related directives (single/multiple/ngOptions) can provide specific versions of
`SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting
the `$viewValue` in or out of the actual `<select>` element and its `<option>` children.

BREAKING CHANGE:

When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element.
This commit changes the actual string used as the surrogate key. We now store a string that is computed
by calling `hashKey` on the item in the options collection; previously it was the index or key of the
item in the collection.

(This is in keeping with the way that the unknown option value is represented in the select directive.)

Before you might have seen:

```
<select ng-model="x" ng-option="i in items">
  <option value="1">a</option>
  <option value="2">b</option>
  <option value="3">c</option>
  <option value="4">d</option>
</select>
```

Now it will be something like:

```
<select ng-model="x" ng-option="i in items">
  <option value="string:a">a</option>
  <option value="string:b">b</option>
  <option value="string:c">c</option>
  <option value="string:d">d</option>
</select>
```

If your application code relied on this value, which it shouldn't, then you will need to modify your
application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions`
as this provides the ability to specify the key that is stored.

Closes angular#8019
Closes angular#9714
Closes angular#10639
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Jan 11, 2015
…ns are loaded async

**Major reworking of select and ngOptions**:

* The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives
to override to get their desired behaviour
* The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions`
directive could be deleted without having to make any changes to the `select` directive.
* Select related directives (single/multiple/ngOptions) can provide specific versions of
`SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting
the `$viewValue` in or out of the actual `<select>` element and its `<option>` children.

BREAKING CHANGE:

When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element.
This commit changes the actual string used as the surrogate key. We now store a string that is computed
by calling `hashKey` on the item in the options collection; previously it was the index or key of the
item in the collection.

(This is in keeping with the way that the unknown option value is represented in the select directive.)

Before you might have seen:

```
<select ng-model="x" ng-option="i in items">
  <option value="1">a</option>
  <option value="2">b</option>
  <option value="3">c</option>
  <option value="4">d</option>
</select>
```

Now it will be something like:

```
<select ng-model="x" ng-option="i in items">
  <option value="string:a">a</option>
  <option value="string:b">b</option>
  <option value="string:c">c</option>
  <option value="string:d">d</option>
</select>
```

If your application code relied on this value, which it shouldn't, then you will need to modify your
application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions`
as this provides the ability to specify the key that is stored.

Closes angular#8019
Closes angular#9714
Closes angular#10639
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Jan 12, 2015
…ns are loaded async

**Major reworking of select and ngOptions**:

* The `SelectController` is now used as an abstraction for the `select` and `ngOptions` directives
to override to get their desired behaviour
* The `select` directive is completely oblivious to the ngOptions directive now - the `ngOptions`
directive could be deleted without having to make any changes to the `select` directive.
* Select related directives (single/multiple/ngOptions) can provide specific versions of
`SelectController.writeValue` and `SelectController.readValue`, which are responsible for getting
the `$viewValue` in or out of the actual `<select>` element and its `<option>` children.

BREAKING CHANGE:

When using `ngOptions`: the directive applies a surrogate key as the value of the `<option>` element.
This commit changes the actual string used as the surrogate key. We now store a string that is computed
by calling `hashKey` on the item in the options collection; previously it was the index or key of the
item in the collection.

(This is in keeping with the way that the unknown option value is represented in the select directive.)

Before you might have seen:

```
<select ng-model="x" ng-option="i in items">
  <option value="1">a</option>
  <option value="2">b</option>
  <option value="3">c</option>
  <option value="4">d</option>
</select>
```

Now it will be something like:

```
<select ng-model="x" ng-option="i in items">
  <option value="string:a">a</option>
  <option value="string:b">b</option>
  <option value="string:c">c</option>
  <option value="string:d">d</option>
</select>
```

If your application code relied on this value, which it shouldn't, then you will need to modify your
application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions`
as this provides the ability to specify the key that is stored.

BREAKING CHANGE:

When iterating over an object's properties using the `(key, value) in obj` syntax
the order of the elements used to be sorted alphabetically. This was an artificial
attempt to create a deterministic ordering since browsers don't guarantee the order.
But in practice this is not what people want and so this change iterates over properties
in the order they are returned by Object.keys(obj), which is almost always the order
in which the properties were defined.

Closes angular#8019
Closes angular#9714
Closes angular#10639
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants