Pesquisa de site

javascript - usar xhr.onprogress para processar download ajax grande sem ficar sem memória?


Diga que minha empresa fornece um grande arquivo de log (mais de 4 GB), onde os logs mais recentes estão no topo. Quero criar uma página da web para buscar nesse arquivo uma palavra-chave "Mike". A largura de banda não é uma restrição, mas esta página da web só pode ser arquivos estáticos (ou seja, sem funcionalidade do lado do servidor).

Arquivo de log de exemplo:

Joe completed Task 1234 on 2013-10-10
Joe completed Task 1235 on 2013-10-11
Mike completed Task 1236 on 2013-10-11
Joe completed Task 1237 on 2013-10-13
...

Obviamente, não posso colocar o arquivo inteiro na memória no navegador, então estou tentando encontrar uma maneira de solicitar o arquivo, buscar os dados à medida que são baixados e depois descartar os dados não relevantes para economizar memória. Estou usando o evento xhr.onprogress para obter o arquivo de log parcialmente baixado via xhr.responseText e pesquisá-lo, mas não consigo redefinir o responseText depois de terminar de lê-lo.

Aqui está meu algoritmo até agora:

var xhr = new XMLHttpRequest();
xhr.onprogress = function(e){
    var cur_len = xhr.responseText.length;
    var found_mike = xhr.responseText.indexOf("Mike") != -1 ? true : false;
    xhr.responseText = ""; //clear responseText to save memory
    console.log("%d - %s - %d", cur_len, found_mike, xhr.responseText.length);
};
xhr.open("get", "mylogfile.txt", true);
xhr.send();

Eu esperaria que o console dissesse algo como 234343 - false - 0, mas em vez disso obtenho 234343 - false - 234343, e o navegador fica sem memória (já que responseText não está sendo limpo).

Existe uma maneira de descartar o responseText para que o navegador possa baixar e processar um arquivo sem manter todo o arquivo na memória?

EDITAR: Além disso, se responseText for somente leitura, por que ele não lança um erro/aviso?

Resposta #1

Depois de perguntar a um amigo, ele teve uma ótima resposta: cabeçalhos de intervalo (pergunta no Stack Overflow, jsfiddle)

var chunk_size = 100000; //100kb chunks
var regexp = /Mike/g;
var mikes = [];
function next_chunk(pos, file_len){
    if(pos > file_len){
        return;
    }
    var chunk_end = pos + chunk_size < file_len ? pos + chunk_size : file_len;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 206){
            //push mikes to result
            while ((match = regexp.exec(xhr.responseText)) != null) {
                mikes.push(pos + match.index);
            }
            //request next chunk
            file_len = parseInt(xhr.getResponseHeader("Content-Range").split("/")[1]);
            next_chunk(chunk_end + 1, file_len);
        }
    };
    xhr.open("get", "mylogfile.txt", true);
    xhr.setRequestHeader("Range", "bytes=" + pos + "-" + chunk_end);
    xhr.send();
}
next_chunk(0, chunk_size);