Search code examples
javascriptnpapibrowser-pluginfirebreath

Efficient scrolling of piped output in a browser window


I have a custom browser plugin (built with FireBreath) that will invoke a local process on a users machine and pipe stdout back to the browser, to do this i'm running the process through a popen() call and as I read data from the pipe I fire a JSAPI event and send it back to the browser.

In the browser I append the output to a div as pre-formatted text and tell the div to scroll to the bottom.

Code in the browser plugin:

FILE* in;
if(!(in = _popen(command_string, "r")))
{
    return NULL;
}

while(fgets(buff, sizeof(buff), in)!=NULL)
{
    send_output_to_browser(buff);
}

HTML & Javascript/jQuery:

<pre id="sync_status_window" style="overflow:scroll">
    <span id="sync_output"></span>
</pre>


var onPluginTextReceived = function (text)
{
    $('#sync_output').append(text);   
    var objDiv = document.getElementById('sync_status_window');
    objDiv.scrollTop = objDiv.scrollHeight;
}

This method works for the browsers I need it to (this is a limited use internal tool), but it's frustratingly laggy. My process usually finishes about 30-60 seconds before the output window finishes scrolling. So, how do I make this more efficient? Is there a better way to pipe this text back to the browser?


Solution

  • There are two optimizations I see potential in:

    1. keep a reference to your pre and span, you keep repeating the dom tree search , which is quite costly
    2. Chunk up the output - either on the C side (preferable) or on the JS side.

    For quick hack (without removing dependency on jquery, which should be done) could look like

    //Higher or global scope
    var pluginBuffer=[];
    var pluginTimeout=false;
    var sync_status_window=document.getElementById('sync_status_window');
    
    function onPluginTextReceived(text)
    {
        pluginBuffer[pluginBuffer.length]=text;
        if (!pluginTimeout) pluginTimeout=window.SetTimeout('onPluginTimer();',333);
    }
    
    function onPluginTimer()
    {
        var txt=pluginBuffer.join('');
        pluginBuffer=[];
        pluginTimeout=false;
        $('#sync_output').append(text);
        sync_status_window.scrollTop = sync_status_window.scrollHeight;
     }
    

    Adapt to your needs, I chose 333ms for 3 updates/second