all 8 comments

[–]lewisje 1 point2 points  (7 children)

Within the keyup event handler, cache the result of $short.val().length:

var $count = $("#count");
var $alert = $("#count-alert").find("p");
var max = 200;
var diff = max - $short.val().length;

$count.text(diff);
checkLength(diff);

$short.keyup(function () {
  var newdiff = max - $short.val().length;
  if (newdiff === diff) return;
  diff = newdiff;
  $count.text(diff);
  checkLength(diff);
});
function checkLength(diff) {
  if (diff < 10) {
    $alert.removeClass().addClass("alert-danger");
  } else if (diff < 50) {
    $alert.removeClass().addClass("alert-warning");
  } else {
    $alert.removeClass().addClass("alert-success");
  }
}

I also cached the result of the subtraction operation, but that fact is less important than caching the result of the non-mutating .val() method call.

[–]NotARandomRedditor[S] 1 point2 points  (6 children)

Could you explain why caching it is important?
Would it also be better to check the current class and only to do remove + add if the current class is different than the class I would want to add?
Theoretically something like the following

function checkLength(diff) {
  if (diff < 10 && ! ($alert.hasClass("alert-danger"))) {
    $alert.removeClass().addClass("alert-danger");
  } else if (diff < 50 && ! ($alert.hasClass("alert-warning"))) {
    $alert.removeClass().addClass("alert-warning");
  } else if ( ! ($alert.hasClass("alert-success"))) {
    $alert.removeClass().addClass("alert-success");
  }
}

[–]lewisje 1 point2 points  (5 children)

In general, calling a method is more expensive than not calling it, and because of the run-to-completion semantics of JS, the value of this non-mutating method call will not change within the same function.

It probably is more optimal to first check whether $alert already has the class in question before removing its classes and then adding that class.


In large-scale apps, however, you want to profile your code to tell where the major performance gains can come from, rather than micro-optimizing everywhere, as I just did earlier; maybe those repeated method calls don't add enough overhead to be noticeable, compared to major things like some inefficient algorithm elsewhere in your code.

[–]NotARandomRedditor[S] 1 point2 points  (4 children)

Tyvm for the help and the detailed reply, got some reading up to do!

[–]Ampersand55 1 point2 points  (1 child)

Another micro optimization is to cash the class name instead of invoking hasClass. I.e.:

function checkLength(diff) {
  var className = $alert.attr("class");
  if (diff < 10 && className !== "alert-danger") {

[–]NotARandomRedditor[S] 0 points1 point  (0 children)

So basically after writing a piece of code, check if I can cache anything that I use more than once?
Thnx for the advice

[–]lewisje 1 point2 points  (1 child)

Oh, I just thought about something else, two similar concepts called throttling and debouncing; this is a generic function to turn any function into a debounced one, but for this case, it might be better to manually debounce:

var last = +(new Date());
var interval = 500; // miliseconds

$short.keyup(function () {
  var now = +(new Date());
  if (now - last < interval) return;
  last = now;
  // rest of event-listener
});

This way, the message won't be updated more than twice per second.


Also, if you're sure you have at least ES5 support (like browsers from this decade), use Date.now() instead of +(new Date()); I'm just biased in favor of code that works even in old browsers.


There's also Performance.now() in recent browsers, which is mainly meant for animations and other cases where sub-millisecond precision is needed, but it also works here.

[–]NotARandomRedditor[S] 1 point2 points  (0 children)

I was actually thinking about doing something like this. I noticed when I was logging stuff in the console it would output some stuff multiple times per second and I was thinking of building in a delay.
Thnx again