Help optimizing a function to count the rows in a textarea I am writing a script to count the number of rows in a textarea, and as it will be called on every keypress I want to make sure it runs as fast as possible. I'm not aiming for a general solution: we can assume that the textarea has a monospace font and enough horizontal space for exactly 80 characters.

I've probably solved this problem in 20 different ways, and this is by far the fastest solution I've come up with:

function countRows1(txt) {
    var i, len, rows = 0;
    txt = txt.split('\n');
    len = txt.length;
    for (i = 0; i &lt; len; i++) {
        rows += Math.ceil(txt[i].length / 80) || 1;
    }
    return rows;
}


Here's a second solution, which is slightly faster in Firefox, but otherwise between a little and 5x slower:

function countRows2(txt) {
    var i = 0, nextBreak, rows = 0;
    while ((nextBreak = txt.indexOf('\n', i)) !== -1) {
        rows += Math.ceil((nextBreak - i) / 80) || 1;
        i = nextBreak + 1;
    }
    return rows + (Math.ceil((txt.length - i) / 80) || 1);
}


The performance doesn't make any sense to me - countRows2 does the same thing as countRows1, except it doesn't create any unnecessary strings or arrays. Is indexOf with a start position just really slow, or is there some optimization only the first method is picking up on?

Finally, here's one more method, which is much slower in every browser I've tested, but beautifully concise:

function countRows3(txt) {
    return txt.match(/\n?[^\n]{1,80}|\n/g).length;
}


Here's the jsPerf I'm using to compare the three.

So I've really got three questions:


Why is countRows2 slower than countRows1?
Is there any way to optimize the regex in countRows3 so the performance is comparable to the first two?
Is there any other way to speed up this code?


ps: I can't just do something like el.scrollHeight, because I need it to shrink as text is deleted. Also, I don't want to remember the previous count and just calculate the difference, because some changes will inevitably be missed and a differential script will never right itself.
What kind of performance are you getting?  Is it acceptable.  If it's not, then I'd look for changing your algorithm, and not minor tweaks.  In particular, I'd look into NOT splitting the string and recalclating each time.  Instead keep track of the state (what line and the number of characters on that line, whether it's a paste or a delete), and do the right thing based upon that.  Adding an additional character at the end of a 5k block of text, adds one more line at most, if the last line was 1 character long, then unless the key being pressed is the enter key, it doesn't even do that.  

But before doing anything, sit down and see how well your existing function works, for your typcial data, and then for some extreme data.