0

I have some json array Data which have hundred of objects with data structure similar to following

var json = [{"id":"123","name":"user"},{"id":"124","name":"user2"},{"id":"125","name":"user4"}] 

I am creating dropdown using this data (ul and li) by using following function

var newhtml = $("<div/>"); json.forEach(function (e) { newhtml.append('<li>'+e.name+'</li>'); }); $('ul').append(newhtml.html());

This is working fine but the problem is if json data goes near thousand it slows down. I already googled and found few ways which includes:

  • Avoid appending li to ul every time. So I append only once after forEach loop. It optimize things to not that much.

Now my question is How to create html using json data with optimized way ?

6
  • Is there much use in displaying 1000+ items at once? Can you break them down & show on demand - autocomplete search, clicking a first letter link? If not pushing each into an array, joining to get an HTML string then setting html()/innerHTML once would be faster. Commented Jul 21, 2017 at 10:23
  • Using for-loop and native methods (= no jQuery) might speed up things a bit. But if there's a ton of new HTML to add to the DOM, there's not much you can do, it will take some time from browser to parse it all, if you want to append it all in a single chunk. Commented Jul 21, 2017 at 10:24
  • use web worker and append data in chunks...let say 500 each time...by listening message event Commented Jul 21, 2017 at 10:25
  • actually i want to append all data at once and option to select one of them and i will also give user option to search Commented Jul 21, 2017 at 10:25
  • 2
    1000 items is far too many for a user to visually filter in the first place Commented Jul 21, 2017 at 10:42

6 Answers 6

5

It will be faster if you don't create the elements until the end. Create the raw HTML first and generate the elements last.

var list = json.map(function(user){ return '<li>' + user.name + '</li>'; }); $('<div/>').html( list.join('') ).appendTo('ul'); 

As @Kannan J pointed out, it's even faster if you skip the join.

var html = json.reduce(function(str, user){ return str += '<li>' + user.name + '</li>'; }, ''); $('<div/>').html( html ).appendTo('ul'); 
Sign up to request clarification or add additional context in comments.

3 Comments

since performance is concern, do we need map and join to do 2 traversals, you could do one pass with for iteration to concatenate in one go.
div is used only for storing markup, it is not actually appended to ul
Working fine thnks
1

You can try to put the full list of li in DocumentFragment and after the loop finishes add it to the DOM. Another solution would be to hold the list of li in DocumentFragment and add it to the DOM in parts, for that case you have to check where is the scroller, something like a infiti-scroll, where new content is added when you reach the bottom of the page.

var fragment = document.createDocumentFragment() json.forEach(function (e) { var li = document.createElement('li') li.innerText = e.name; fragment.appendChild(li) } ul.appendChild(fragment); 

Example with scroll:

var next = 50; var ul = document.getElementById('ul'); ul.addEventListener('scroll', function(ev) { var a = ev.target.scrollTop; var b = ev.target.scrollHeight - ev.target.clientHeight; if((a / b) > 0.9) { //add next part of li's to the ul var part = document.createDocumentFragment(); var start = next; next += next; [].slice.call(fragment.children, start, next).map(function(li) { part.appendChild(li); }); ul.appendChild(part) } }); 

Comments

0

this way

var json = []; var length = 100000; while(length--){ json.push({id: length, name: length}); } var time = new Date().getTime(); var dropdown = document.createElement('select'); json.forEach(function(item){ var option = document.createElement('option'); option.innerHTML = item.name; option.value = item.id; dropdown.appendChild(option); }) console.log(new Date().getTime() - time) 

As I see 100000 elements take less than 2 sec, 10000 around 180 mcs

17 Comments

option elements don't have innerHTML.
prooflink, please.
@degr i dont think this will help me a lot since it almost using the same way
@Teemu cool, please read about OOP and developer.mozilla.org/en-US/docs/Web/API/Node
The real problem is probably that the OP doesn't have options, nor a select, but an unordered list ?
|
0

Another option - building HTML then updating the DOM once:

var buffer = [] $.each(json, function(key, value) { buffer.push('<li>' + value.name + '</li>'); }); $('ul').append(buffer.join("")); 

Comments

0

Iterate once, add to simple string and insert one shot

var options = ""; for (var i = 0 ; i < json.length; i++) { options += "<li>" + json[i].name + "</li>" } $('ul').append(options);

Comments

0

Whenever speed is an issue:

  1. Use simple for loops instead of forEach

  2. Don't concatenate strings with + in loops. Instead, add items to an array and join them

Example:

var newHtml = []; for(var j=0, jsonLen=json.length; j<jsonLen; j++){ newHtml.push('<li>'+json[j].name+'</li>') } $('ul').append(newHtml.join('')); 

From my test, its about 6x faster than your solution. For 10.000 items, duration was reduced from 453ms to 77ms. (demo)

However, as Alex K. suggested, you should avoid generating thousand elements at once. Besides the performance issue its not user-friendly either. I recommend finding another solution such as generating elements while user scrolls or making him use a search/autocomplete function.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.