javascript - använd xhr.onprogress för att bearbeta stor ajax-nedladdning utan att få slut på minne?
Säg att mitt företag tillhandahåller en stor loggfil (4+ GB), där de senaste loggarna är överst. Jag vill bygga en webbsida för att söka i den filen efter nyckelordet "Mike". Bandbredd är inget problem, men denna webbsida kan endast bestå av statiska filer (dvs. ingen serverfunktionalitet).
Exempel på loggfil:
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
...
Självklart kan jag inte lägga hela filen i minnet i webbläsaren, så jag försöker hitta ett sätt att begära filen, söka i datan medan den laddas ner, och sedan kasta bort icke-relevant data för att spara minne. Jag använder xhr.onprogress-händelsen för att få den delvis nedladdade loggfilen via xhr.responseText och söka i den, men jag kan inte återställa responseText efter att jag är klar med att läsa den.
Här är min algoritm hittills:
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();
Jag skulle förvänta mig att konsolen säger något i stil med 234343 - false - 0, men istället får jag 234343 - false - 234343, och webbläsaren får slut på minne (eftersom responseText inte rensas).
Finns det ett sätt jag kan kassera responseText så att webbläsaren kan ladda ner och bearbeta en fil utan att hålla hela filen i minnet?
REDIGERA: Dessutom, om responseText är skrivskyddad, varför ger det då inget felmeddelande/varning?
Svar #1
Efter att ha frågat en vän, och han hade ett bra svar: Range headers (stackoverflow-fråga, 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);
