Neatest (and fast) way to remove top lines from a

2020-04-12 08:13发布

问题:

I have a webpage that displays last 1000 lines of a logfile then updates via AJAX every x seconds loading new content (if any) and appending to textarea with $('#log').append(new_data), a sort of tail -f.

The problems come up after some time when too many lines are appended and the page becomes slow or unresponsive.

So I'd like to limit number of lines to, say, 5000 so it means I should:

  • retrieve new_data
  • calculate overflow = 5000 - lines_ in_new_data - lines_in_textarea
  • if overflow > 0 remove first overflow lines from textarea
  • append new_data to textarea

In my mind this involves one or more split('\n') of both textarea and new_data values then use array lengths and slicing but I guess if there's a neater or better way to accomplish this.

回答1:

You should be able to use a single split and then join after truncating the data, something like this:

// on data retrieved
var total = ((textarea.value 
              ? textarea.value + "\n" 
              : "") 
          + new_data).split("\n");

if (total.length > 10) 
    total = total.slice(total.length - 10);

textarea.value = total.join("\n");

Working example: http://jsfiddle.net/ArvQ7/ (cut to 10 lines for brevity)



回答2:

Something like this (demo linked below is probably more useful):

HTML

<button id="clickme">More lines</button>
<br/>
<textarea id="log" rows="24" cols="80"></textarea>
<p>Lines: <span id="numLines">0</span></p>

JavaScript

var $log = $('#log'),
    $button = $('#clickme'),
    $numLines = $('#numLines'),
    MAX_LINES = 5000,
    lorem_ipsum = ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    lineCounter = 0;

$button.click(function()
{
    $log.val($log.val() + generateMoreLines()).change();
});

$log.change(function ()
{
    var text = tail(MAX_LINES, $log.val());
    $log.val(text);
    $numLines.text(countNewlines(text));
});

function generateMoreLines()
{
    var buf = [];
    for (var i = 0; i < 1000; i++)
    {
        buf.push(lineCounter++ + lorem_ipsum);
    }
    return buf.join('\n');
}

function countNewlines(haystack)
{
    return count('\n', haystack);
}

function count(needle, haystack)
{
    var num = 0,
        len = haystack.length;
    for (var i=0; i < len; i++)
    {
        if (haystack.charAt(i) === needle)
        {
             num++;
        }
    }
    return num;
}

function tail(limit, haystack)
{
    var lines = countNewlines(haystack) + 1;
    if (lines > limit)
    {
        return haystack
            .split('\n')
            .slice(-limit)
            .join('\n');
    }
    return haystack;
}

The newline handling isn't perfect (do you count all occurrences of '\n'? What if the string starts or ends with '\n'? etc.).

Demo: http://jsfiddle.net/mattball/3ghjm/