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);
