Big file upload causes browser to hang - javascript

Small files go smoothly, even when uploading 100 5 Megabyte files at the same time (though it does only handle 5 at a time, queues the rest) but a 150MB file causes the browser to hang several seconds while it initiates.
function start(file) {
var xhr = new XMLHttpRequest();
++count;
var container = document.createElement("tr");
var line = document.createElement("td");
container.appendChild(line);
line.textContent = count + ".";
var filename = document.createElement("td");
container.appendChild(filename);
filename.textContent = file.fileName;
filename.className = "filename";
initXHREventTarget(xhr.upload, container);
var tbody = document.getElementById('tbody');
tbody.appendChild(container);
tbody.style.display = "";
var boundary = "xxxxxxxxx";
xhr.open("POST", "uploader.php");
xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary); // simulate a file MIME POST request.
xhr.setRequestHeader("Content-Length", file.size);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) {
if (xhr.responseText != "") {
alert(xhr.responseText); // display response.
}
}
}
}
var body = "--" + boundary + "\r\n";
body += "Content-Disposition: form-data; name='upload'; filename='" + file.fileName + "'\r\n";
body += "Content-Type: application/octet-stream\r\n\r\n";
body += $.base64Encode(file.getAsBinary()) + "\r\n";
body += "--" + boundary + "--";
xhr.sendAsBinary(body);
}

It IS going to take a non-trivial amount of time to slurp in the file's contents, base64 encode it, and then do your string concatenation. In other words: Behaving as expected.

Related

XHR POST request with multi files using FileReader API

This is my first question on StackOverflow :)
I'm learning Javascript for a personal project and I get some troubles with asynchronous functions. Something is not clear to me yet with such functions :( .
I try to upload multifiles in an HTML form to prepare an XHR request. Below is my function that I trigger with a an AddEventListener on the submit button.
I found explications on MDN learning web development but since it was only for one file I custom it with a for loop on formCell[5].files (declared as global constant) which is where my files are.
The problem seems to be with the asynchronous behavior. Is an expert on stack have advice to me ? Is there a solution with promises for example ? The "If" with SetTimeOut to wait for loop execution don't seem to me very pretty.
I think I tried hundred solutions without success :)
Thanks a lot in advance,
Regards,
Romain
function sendData() {
/* Loading files */
var binnaryFiles = [null];
for (let i = 0; i < formCell[5].files.length; i++) {
let reader = new FileReader(); // FileReader API
reader.addEventListener("load", function () { // Asynchronous function (return result when read)
binnaryFiles[i] = reader.result;
});
// Read the file
reader.readAsBinaryString(formCell[5].files[i]);
}
if(binnaryFiles.length !== formCell[5].files.length) {
setTimeout( sendData, 10 );
return;
}
console.log("final" + binnaryFiles.length);
const XHR = new XMLHttpRequest();
const boundary = "blob"; // We need a separator to define each part of the request
let msg = "";
/* Loading files in the request */
for (let i = 0; i < formCell[5].files.length; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; '
+ 'name="' + formCell[5].name + '"; '
+ 'filename="' + formCell[5].files[i].name + '"\r\n';
msg += 'Content-Type: ' + formCell[5].files[i].type + '\r\n';
msg += '\r\n';
msg += binnaryFiles[i] + '\r\n';
}
/* Loading texts in the request */
for (let i = 0; i < formCell.length - 1; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; name="' + formCell[i].name + '"\r\n';
msg += '\r\n';
msg += formCell[i].value + "\r\n";
}
msg += "--" + boundary + "--";
XHR.addEventListener("load", function(event) {
alert( 'Yeah! Data sent and response loaded.' );
});
XHR.addEventListener("error", function(event) {
alert("Oops! Something went wrong.");
} );
XHR.open("POST", "http://localhost:3000/upload");
XHR.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
XHR.send(msg);
console.log(msg);
}
I think I finished by solving my problem using Promises :)
If anyone could confirm me that the code below is correct it could help me :)
Thanks,
Romain
function fileUpLoad(fileToUpload) {
return new Promise((resolve, reject) => {
const reader = new FileReader(); // FileReader API
reader.addEventListener("load", function () { // Asynchronous function (return result when read)
resolve(reader.result);
reject(reader.error);
});
// Read the file
reader.readAsBinaryString(fileToUpload);
});
}
/* Sending message */
function sendData(filesUploaded) {
let binnaryFiles = filesUploaded;
const XHR = new XMLHttpRequest();
const boundary = "blob"; // We need a separator to define each part of the request
let msg = "";
/* Loading files in the request */
for (let i = 0; i < binnaryFiles.length; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; '
+ 'name="' + formCell[5].name + '"; '
+ 'filename="' + formCell[5].files[i].name + '"\r\n';
msg += 'Content-Type: ' + formCell[5].files[i].type + '\r\n';
msg += '\r\n';
msg += binnaryFiles[i] + '\r\n';
}
/* Loading texts in the request */
for (let i = 0; i < formCell.length - 1; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; name="' + formCell[i].name + '"\r\n';
msg += '\r\n';
msg += formCell[i].value + "\r\n";
}
msg += "--" + boundary + "--";
XHR.addEventListener("load", function(event) {
alert( 'Yeah! Data sent and response loaded.' );
});
XHR.addEventListener("error", function(event) {
alert("Oops! Something went wrong.");
} );
XHR.open("POST", "http://localhost:3000/upload");
XHR.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
XHR.send(msg);
console.log(msg);
}
/* Validation on submit calling */
form.addEventListener("submit", function (evt) {
evt.preventDefault();
if (validationOnSubmit()) {
if (formCell[5].files.length > 0) {
let fileUploadingPromise = []
for (let i = 0; i < formCell[5].files.length; i++) {
fileUploadingPromise[i] = fileUpLoad(formCell[5].files[i]);
}
let binnaryFiles = [null];
Promise.all(fileUploadingPromise)
.then (resolve => {
for (let i = 0; i < formCell[5].files.length; i++) {
binnaryFiles[i] = resolve[i];
}
sendData(binnaryFiles)
})
.catch (reject => {
console.log(reject);
});
} else {
sendData(0);
}
}
});

I've got "The object's state must be OPENED."

I've tried to perform AJAX request, but I've got this kind of error, that ajax call should be opened. But it is opened already. Trying to send the XMLHttpRequest header, but getting this kinda error. Guys, help me!
let del_btn = document.querySelectorAll('.delete');
for(let i = 0; i < del_btn.length; i++)
{
del_btn[i].addEventListener('click', function(){
let xhr = new XMLHttpRequest();
let book_title = del_btn[i].parentElement.children[1].children[1].children[0].children[0].textContent;
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4 && xhr.status == 200)
{
if(this.responseText.includes('Deleted'))
{
let books = this.responseText.split('.')[1];
if(books == '0')
{
del_btn[i].parentElement.parentElement.innerHTML = 'You have no books in your list. Go to the ' + ' ' + ' main page ' + ' ' + 'and start your ride!';
}
else
{
del_btn[i].parentElement.parentElement.removeChild(del_btn[i].parentElement);
document.querySelector('.amount-b').textContent = 'Количество книг: ' + books;
}
}
}
}
xhr.open("POST", "../operations/delete_book.php", true);
xml.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('title=' + book_title);
}, false);
}```

Request Data from one API according to the data recolted on another API

I'm using two functions to get some data from an API :
The first one request the data for each cycle, the second check if the payment has been done for each cycle.
All the data are placed in a common table. It seems that my issue come from the fact that I use a function in another function. It the that the second function executes itself only after the first one is complete.
https://codepen.io/anon/pen/XQOVVB?editors=1001
var obj, obj2, dbParam,dbParam2, xmlhttp, xmlhttp2, myObj, myObj2, x, y, txt, txt2 = "";
obj = { table: "cycle", limit: 10 };
dbParam = JSON.stringify(obj);
xmlhttp = new XMLHttpRequest();
// Get the value of the inputbox
// KT1 adress for trial KT19www5fiQNAiqTWrugTVLm9FB3th5DzH54
var KT1 = $('#KT1').val();
xmlhttp.onreadystatechange = function() {
obj2 = { table: "cycle2", limit: 100 };
if (this.readyState == 4 && this.status == 200) {
myObj = JSON.parse(this.responseText);
txt += "<table><tr bgcolor=#000000 color=White>"
txt += "<th>Cycle</th>"
//txt += "<th>Reward</th>"
txt += "<th>Paid</th>"
txt += "</tr>"
// Get the data of every cycle using API 1
for (x in myObj) {
// force x to 11 to get the condition PaymentCycle = cycle
x = 11;
cycle = myObj[x].cycle;
//balance = myObj[x].balance/1000000;
//TotalReward = myObj[x].rewards/1000000;
//stakingBalance = myObj[x].staking_balance/1000000;
//Share = balance/stakingBalance*100;
//DelegatorReward = Share*TotalReward/100;
// create line of the table
txt += "<tr>";
txt += "<td width=10% align=center>" + cycle + "</td>";
//txt += "<td width=10% align=center>" + Math.round(DelegatorReward*100)/100 + "</td>";
// here the CYCLE CHANGE CORRECTLY from 106 to 87
console.log("Cycle before function: " + cycle);
//API2 request
dbParam2 = JSON.stringify(obj2);
xmlhttp2 = new XMLHttpRequest();
xmlhttp2.onreadystatechange = function() {
if (this.readyState == 4 && (this.status == 200 || this.status == 0)) {
myObj2 = JSON.parse(this.responseText);
// ERROR HERE - ALWAYS GET THE DATA OF THE LAST CYCLE (87) instead of every cycle check with API1
// It seems that this fonction xmlhttp2 is executed only after xmlhttp is complete giving to cycle the last value of saved for cycle (87)
console.log("Cycle after function: " + cycle);
for (var y = 0; y < 30; y++) {
// Get the Paiement cycle which varies from 106 to 90
Block = myObj2[y].type.operations[0].op_level;
PaiementCycle = Math.round(Block/4096);
PaiementCycle = PaiementCycle - 6;
// If the Data entered in the input box = of the destination adress of API 2 and the cycle of API1 and API2 is the same then
// Here cycle is always = 87 (Last value of the API1 reading (before the function the cycle change from 106 to 87).
// I really don't understand why
if (KT1 == myObj2[y].type.operations[0].destination.tz && PaiementCycle == cycle) {
console.log("Get one");
console.log("Paiement Cycle : " + PaiementCycle);
Paid = "/////////////////" + myObj2[y].type.operations[0].amount/1000000;
console.log("Paid : " + Paid);
txt += "<td width=10% align=center>Paiement :" + Paid + "</td>";
txt += "</tr>";
// All the data saved during this function is saved after the execution or the boucle for(x)
console.log("Txt /////: " + txt);
// document.getElementById("demo2").innerHTML = txt2;
} else {
}//
}
//return txt;
} else {
//console.log("Not Ok");
}
};
xmlhttp2.open("POST", "https://api6.tzscan.io/v3/operations/tz1XynULiFpVVguYbYeopHTkLZFzapvhZQxs?type=Transaction&number=100", true);
xmlhttp2.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp2.send("x=" + dbParam2);
}
txt += "</table>";
console.log("Txt 2 : " + txt);
document.getElementById("demo").innerHTML = txt;
}
};
xmlhttp.open("POST", "https://api6.tzscan.io/v3/delegator_rewards_with_details/" + KT1, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send("x=" + dbParam);
You can see here my codepen, you can easily see that my function xmlhttp2.onreadystatechange = function() { only executes itself after xmlhttp.onreadystatechange = function() { instead of after getting each data from the JSON file
try to use JavaScript Promises.
A simple Promise is here

getting XMLHttpRequest cannot load (URL) Response for preflight is invalid (redirect)

here am trying to get reccurring events from calendar list for sharepoint Online app and there am using code as like
hostWebUrl = decodeURIComponent(manageQueryStringParameter('SPHostUrl'));
function GetListData() {
var webUrl = hostWebUrl;// = "http://server/sitewhereyourlistexists";
var listGuid = "{2000da75-8663-42d9-9999-ad855c54b4e0}"
// An XMLHttpRequest object is used to access the web service
var xhr = new XMLHttpRequest();
var url = webUrl + "/_vti_bin/Lists.asmx";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xhr.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetListItems");
// The message body consists of an XML document
// with SOAP elements corresponding to the GetListItems method parameters
// i.e. listName, query, and queryOptions
var data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<GetListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">" +
"<listName>" + listGuid + "</listName>" +
"<query>" +
"<Query><Where>" +
"<DateRangesOverlap>" +
"<FieldRef Name=\"EventDate\"/>" +
"<FieldRef Name=\"EndDate\"/>" +
"<FieldRef Name=\"RecurrenceID\"/>" +
"<Value Type=\"DateTime\"><Today/></Value>" +
"</DateRangesOverlap>" +
"</Where></Query>" +
"</query>" +
"<queryOptions>" +
"<QueryOptions>" +
"<ExpandRecurrence>TRUE</ExpandRecurrence>" +
"</QueryOptions>" +
"</queryOptions>" +
"</GetListItems>" +
"</soap:Body>" +
"</soap:Envelope>";
// Here we define what code we want to run upon successfully getting the results
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var doc = xhr.responseXML;
// grab all the "row" elements from the XML results
var rows = doc.getElementsByTagName("z:row");
var results = "Today's Schedule (" + rows.length + "):\n\n";
var events = {};
for (var i = 0, len = rows.length; i < len; i++) {
var id = rows[i].getAttribute("ows_FSObjType"); // prevent duplicates from appearing in results
if (!events[id]) {
events[id] = true;
var allDay = rows[i].getAttribute("ows_fAllDayEvent"),
title = rows[i].getAttribute("ows_Title"),
start = rows[i].getAttribute("ows_EventDate");
var index = start.indexOf(" ");
var date = start.substring(5, index) + "-" + start.substring(2, 4); // get the date in MM-dd-yyyy format
start = start.substring(index, index + 6); // get the start time in hh:mm format
var end = rows[i].getAttribute("ows_EndDate");
index = end.indexOf(" "); end = end.substring(index, index + 6); // get the end time in hh:mm format
results += date + " " + (allDay == "1" ? "All Day\t" : start + " to " + end) + " \t " + title + "\n";
}
}
alert(results);
} else {
alert("Error " + xhr.status);
}
}
};
// Finally, we actually kick off the query
xhr.send(data);
}
after calling this function in decument. ready section it is not retrieving any data but there is ine error which i can see in console of browser that is as below
You will click on the correct request in the left hand side panel, then select "Inspectors" in the right hand side top panel. Then choose between the different request and response options.

How to set my HTML Table progressively with Javascript/AJAX and Java Servlet?

Hy everyone! I've got a problem developping a little webapp.
The goal is to search for a specific word in files from a stating folder on the server.
To do that, I've implemented a recursive algorithm using java.io.File and a BufferReader.
When I get the results, I had them in a table using a script in my jsp file :
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
My problem is that with this code, all of the results are printed in one tim in the target table. I would like to see the results comming one by one, everytime a file is found in the algorithm.
I've tried to change the readystate to "3" in the onreadystatestage function :
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
But it doesn't change anything.
Does somebody have an idea? How can I send every founded file one by one ? Do I have t do it in the servlet class ?
The for instruction in the servlet class :
// If the input word name isn't empty, the algorithm is launched.
if (null != wordToSearch && !"".equals(wordToSearch))
{
lstFiles.clear();
searching(new File(contextPath), wordToSearch);
int n = lstFiles.size();
// Priting a message that indicate how many files have been found with the word to search.
emptyFieldMessage = n + " files has been found containing the word '" + wordToSearch + "'!";
output.append("<message>").append(emptyFieldMessage).append("</message>\n");
output.append("<lstFiles>\n");
// Then, files list with :
// - File path in "name" parameter,
// - Number of apparence of the word in "nb" parameter,
// - Formatted path as the value.
for(int i = 0; i < n; i++)
{
output.append("<file name=\"" + lstFiles.get(i) + "\" nb=\"" + lstNbApparence.get(i) + "\" >").append(lstFilesPath.get(i)).append("</file>\n");
}
output.append("</lstFiles>\n");
}
To be more complet, the whole script code :
<script>
// Creating xhr variable.
var xhr = null;
// Creating the "Search" button function.
function request(callback) {
// "Cancel" button case.
if (xhr && xhr.readyState != 0)
{
xhr.abort();
}
// "Search" button case.
else
{
// Calling the good function from external file.
xhr = getXMLHttpRequest();
// Callback and loading icon management.
xhr.onreadystatechange = function() {
if (xhr.readyState >= 3 && (xhr.status == 200 || xhr.status == 0)) {
callback(xhr.responseXML);
document.getElementById("loader").style.display = "none";
document.getElementById("btn").value = "Search";
} else if (xhr.readyState < 3) {
document.getElementById("loader").style.display = "inline";
document.getElementById("btn").value = "Cancel";
}
};
// Calling the Servlet in charge of the recursion algorithm.
var input = encodeURIComponent(document.getElementById("wordName").value);
xhr.open("GET", "/webApp_Search_Merge/ActionServlet?wordName=" + input, true);
xhr.send(null);
}
}
// Creating the reponse function.
function readData(response) {
if (null != response)
{
// Posting the message include in the XML file sending back by the Servlet.
var message = response.getElementsByTagName("message");
document.getElementById("message").innerHTML = message[0].firstChild.nodeValue;
// Posting founded files in a table.
var files = response.getElementsByTagName("file");
// -> Creating the results table.
var table = "<table width=\"100%\">\n";
for (var i = 0, c = files.length; i < c; i++) {
// -> Building the number of apparence in each file.
var nb = files[i].getAttribute("nb");
var nbSentence = "";
if (nb == 1) { nbSentence = nb + " time in this file."; }
else { nbSentence = nb + " times in this file."; }
// Building and filling the table.
if (i % 2 == 0) { table += "<tr class=\"pair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
else { table += "<tr class=\"impair\"><td><a href=" + files[i].firstChild.nodeValue + " target=\"_blank\" >"
+ files[i].getAttribute("name") + "</a></td><td>" + nbSentence + "</td></tr>\n"; }
}
table += "</table>\n";
// -> To end the procedure, we had the table to the right div.
document.getElementById("files").innerHTML = table;
}
}
Thanks by advance for your help, Thomas.
I tried to set up a working demo, but with no results. I was also searching why I can't find the way to "sleep" a function and re-execute after 1000 milliseconds or whatever you want. Already found an answer to that, but I think it's not really what did you expected:
A sleep function will kill the browser and possibly the machine.
Javascript is single threaded, so the browser will block while this
executes, and the loop itself will just take up a lot of CPU. I’ve
heard of some libraries that actually do sleep correctly in an
asynchronous manner, but I can’t remember the name right now.
This is a very bad idea. JavaScript is single threaded so while that
for loop is running nothing else can execute (js timers, browser
events, even the UI in most browsers). Try to sleep for 5 or more
seconds and the browser will even warn the user that a script is
running slowly.
Just use setTimeout.
Also speaks about a sleep function into Native Javascript. It seems that it's like a framework or something like that. You can download it and try it at your own. I can't say anything about this because I've never tested, it's just what I found on internet.
I'm sorry to give you bad news.

Categories