8

Im trying to figure out best practices in regard to performance when creating multiple DIV's at an insane rate. For example, on every .mousemove event...

$('head').append("<style>.draw {width: 20px; height: 20px; position:fixed;</style>");

$(document).mousemove(function(mouseMOVE) {
//current mouse position
    var mouseXcurrent = mouseMOVE.pageX;
    var mouseYcurrent = mouseMOVE.pageY;

//function to create div
   function mouseTRAIL(mouseX, mouseY, COLOR) {
        $('body').append("<div class='draw' style='top:" + mouseY + "px; left:" + mouseX + "px; background: " + COLOR + ";'></div>");
    }

// function call to create <div> at current mouse positiion
   mouseTRAIL(mouseXcurrent, mouseYcurrent, '#00F');

// Remove <div>
    setTimeout(function() {
        $('.draw:first-child').remove();
    }, 250);
});

So, this works all nice and dandy but it's mega inefficient (especially so when I try filling in the space between each mouse move position). Here's an example...

$('head').append("<style>.draw {width: 20px; height: 20px; position:fixed;</style>");

$(document).mousemove(function(mouseMOVE) {
//current mouse position
    var mouseXcurrent = mouseMOVE.pageX;
    var mouseYcurrent = mouseMOVE.pageY;

// function to create div
    function mouseTRAIL(mouseX, mouseY, COLOR) {
        $('body').append("<div class='draw' style='top:" + mouseY + "px; left:" + mouseX + "px; background: " + COLOR + ";'></div>");
    }

// function call to create <div> at current mouse positiion
    mouseTRAIL(mouseXcurrent, mouseYcurrent, '#00F');

// variabls to calculate position between current and last mouse position
    var num = ($('.draw').length) - 3;
    var mouseXold = parseInt($('.draw:eq(' + num + ')').css('left'), 10);
    var mouseYold = parseInt($('.draw:eq(' + num + ')').css('top'), 10);
    var mouseXfill = (mouseXcurrent + mouseXold) / 2;
    var mouseYfill = (mouseYcurrent + mouseYold) / 2;

// if first and last mouse postion exist, function call to create a div between them
    if ($('.draw').length > 2) {
    mouseTRAIL(mouseXfill, mouseYfill, '#F80');
    }

// Remove <div>
    setTimeout(function() {
        $('.draw:first-child').remove();
        $('.draw:nth-child(2)').remove();
    }, 250);
});


I really cant figure out how to improve things. Believe me, Ive tried researching but it hasn't done much good... What I'm looking for is some suggestions, examples, or links to better practices...

Please note that I'm teaching myself to code. I'm a Graphic Design student and this is how I'm spending my summer out of class... Making little projects to teach myself JavasSript, fun stuff :)


Ive set up some jsfiddles to show what Im working on...

Mouse Trail, More Elements - Very Very Slow
Mouse Trail, Less Elements - Very Slow
Mouse Trail, Bare Bones - Slow

Terry
  • 675
  • 2
  • 9
  • 21
  • 1
    +1 for a very interesting project. you should make this a jQuery plugin! It works without problems also, Chrome 19 on Win7 – Joseph May 19 '12 at 09:27
  • 1
    What's very very slow ? It works fine on my macbook – maxdec May 19 '12 at 09:29
  • The Very Very Slow one runs like a charm for me. And I love it. – kapa May 19 '12 at 09:31
  • @Double On my Dual Core Windows7x64 Firefox v12 'Mouse Trail, More Elements' runs choppy when moving the mouse frantically, especially when its filling in more divs between each mousemove http://jsfiddle.net/terry/PzCcZ/ – Terry May 19 '12 at 09:36
  • 2
    At the first glance I only see small things. Move `TRAILS` definition outside (it does not need to be redefined all the time), only calculate values if they are needed (like `mouseXfill75`). Only call `remove()` if they were really created. But these won't give you a big performance benefit. Btw I run it on Chrome on a DualCore Win7x64, and it's perfect. – kapa May 19 '12 at 09:40
  • @Joseph I think I might just make YAP (yet another plugin) :P Also, Thanks! – Terry May 19 '12 at 09:42
  • 1
    @Terry Another one: running `$('.draw').length` twice is inefficient. You should query the DOM once: `var l = $('.draw').length;` and use `l` for the conditions. Even better: don't query the DOM at all (it's "expensive"). Maintain a variable that will always store the current number of `.draw`s. When you add or remove some, change the variable. – kapa May 19 '12 at 09:51
  • @bažmegakapa Thanks for your suggestion, any bit helps, and also your kind words :D – Terry May 19 '12 at 09:53

2 Answers2

3

There are multiple bad practices going on here:

  • Using elements instead of Canvas
  • Using those elements via jQuery
  • Abusing that jQuery as if you were trying to make it slow on purpose
  • Stuffing all of the above inside a mousemove handler

The root issue here really is using elements instead of canvas. After fixing that, the interaction with DOM should become minimal and thus fix the other points as well.

Also, those who claim that this works fine didn't check their CPU usage. On my Core I5-2500K one core is instantly maxed up which is ridiculous and unacceptable for something trivial like rendering a mouse trail on screen. I can very well imagine this being very very slow on an older computer. So yes, it's smooth but at the cost of using amount of resources enough for 10-20+ tabs to do the same properly.

This takes 7-14% cpu for me when moving mouse around fast, this takes full 25%.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • 1
    +1 Good advice. What's wrong with `Using those elements via jQuery`? – kapa May 19 '12 at 14:10
  • @Esailija I agree that using `` would be the practical way to go BUT.. I'm trying to figure out how to execute JavaScript to inject content into the DOM in the most efficient way, more or less, if that makes sense? Ps. +1vote for your suggestion and examples, thank you. – Terry May 20 '12 at 04:34
1

You should be careful not to cause a reflow and stick only to a repaint. -> When does reflow happen in a DOM environment?

So creating <div>s is no option. - But you don't need to :)

Just create as many <div>s as you will need in future and then reposition them. If you have them in an array you'd only need an integer that points to the current most one and on each mouse movement you'd increase that value (set it to 0 once it reaches the array lenght) and reposition the <div> that's pointed to by that number.

Community
  • 1
  • 1
Chris
  • 3,265
  • 5
  • 37
  • 50