I’m working on a project that has some performance issues. One them is one single page that takes more than a minute to show. I analyzed what was going on and the truth was that the page’s size was about 3.5 mb. So, what was making the markup so large? comboboxes. Seventeen comboboxes with about 600 options average (but there was some with 2000 options!).
My first reaction was “Why in the hell they need a combobox with 2000 options? this is a functional failure”. But you know, “it’s what the client wants, it’s too late for chaning it now”.
The first solution we came with was to render only the selected value in the markup and to populate the entire list using ajax when the user clicks/focuses on the combo. The great about it is that the ajax responses could be cached by the server side for reducing the server processing and by the browser, so there’s no need to go find the same items again. Just lovely.
And it worked, and worked fine. Except for Internet Explorer. For some reason, if you change the options collection, the select will close, so the user have to click it again.
Our second approach was to call the populate method when the page loading is complete (aka document.ready). The idea was to have the user filling the form while the combos where loading. And, of course, we could make use of the sweet cache I told before. Well, loading about 9000 options will crash your browser. In this way, it takes more time than the 3.5 mb page! So we moved from adding options using the DOM to use innerHTML, so we can change all the options in one shot. It works perfect in firefox, but for internet explorer… well… This code:
var combo = document.getElementById("combo"); combo.innerHTML = "<option value='1'>Test1</option><option value='2'>Test 2</option>" alert(combo.innerHTML);
Gives me this:
And, of course, it doen’t work. Then, I tried this approach:
var combo = document.getElementById("combo"); var option = new Option(); combo.add(option); option.outerHTML = "<option value='1'>Test1</option><option value='2'>Test 2</option>" alert(combo.innerHTML);
And it gives me the same result!! It just doesn’t make sense at all! At least, Microsoft is aware of it… are you kidding me? it was found in the IE 5.5 era and continues broken?
Changing the combobox outerHTML works, but we miss the reference to the previous combo in the DOM and the ASP.NET Validators stop working.
After days of Internet Explorer induced stress we decide that the problem was actually functional, and called the client. He confirmed that there shouldn’t be so many options and that there should be a configuration problem, so we limited the amount of options to 200 and start working on the configuration issues instead.
In a previous post I introduced you LazyPanel. Now I will talk about how it deals with output cache.
The main problem with output cache is when the cached response is retrieved, the content key is expired:
- Request comes
- Server processes the request
- LazyPanel caches for 3 seconds it’s content and generates a key
- Server returns the response without the lazy content but with an ajax call for retriving it
- Request comes for the content with the generated key
- Server returns the content and removes it from the cache
- A new Request comes
- Server retrieves it from the output cache
- Reqeust comes for the content with the previously generated key
- Server crashes because the key doesn’t exist 😥
Ideally, the content cache should take in care the same stuff that the output cache does, so instead of living 3 seconds, it lives the same time for the same circumstances. Well… “let’s see the code of the output cache” I said… and of course it is all sealed, internal and all the crap. F**k.
I opened the reflector and check the code. I realized that the output cache is stored in the web cache known by all of us and the key is generated using all output cache vars (params, encoding, etc). So, I copied (yes, copied) the strategy for creating the key and use it for storing the content cache. Finally, the duration of the cache is the same of the output cache and it seems to be working perfectly 🙂