Big foreach freeze DOM - javascript

There is a script that processes lines from a text file and sends it to the server. The server, meanwhile, returns a response and fills in the required information.
The problem is that when you try to download a file with about a million entries, the browser freezes and takes a very long time to process.
Is it possible to make this process without browser delays?
document.getElementById('file').onchange = function() {
$('#uploader-after').show();
$('#uploader-before').hide();
$("#file").prop('disabled', true);
var o_time = performance.now();
$('o_total').text("");
$('o_errors').text("");
$('o_time').text("");
var file = this.files[0];
var count = 1;
var errorCount = 0;
$('.file-name').text(file.name);
var reader = new FileReader(file);
reader.onload = function(progressEvent) {
var lines = this.result.split('\n');
$('#find-count').text(lines.length);
for(var line = 0; line < lines.length; line++) {
//setTimeout( function() { // i try this, but dont work
jQuery.ajax({
'async': true,
'global': false,
'type': "POST",
'url': 'getFile.php',
'data': { url: lines[line] },
'dataType': "json",
'success': function(data) {
var answer = data.answer ? data.answer : "";
var id = data.id ? data.id : "";
$('#proc-count').text(count);
var proc = Math.round(count / lines.length * 100);
$('proc').text(proc);
$("#pg-bar-line").css("width", proc + "%");
count++;
if(id == "") {
errorCount++;
}
$('o_total').text(count - 1);
$('o_errors').text(errorCount);
scannert.DataTable().row.add([id, data.inputURL, answer]).draw(false);
if(count === lines.length) {
o_time = performance.now() - o_time;
$('o_time').text(msToTime(o_time));
$('.otchet').show();
$('#uploader-after').hide();
$('#uploader-before').show();
$("#file").prop('disabled', false);
}
},
'error': function() {
count++;
}
});
//}, 5);
}
};
reader.readAsText(file);
};
Ill try setTimeout, but it doesnt work -_-

Related

AJAX keep showing wrong data from array

I have a loop that calls multiples AJAX to find out if there's any booking in the database or not. JS will pass the data from an array to AJAX and find it out in database through SQL query.
However, the data returned from the AJAX is correct, and if it's there in database, i want to to show the data returned from AJAX and the current value of array in current loop, but still the data that i show from the array is the last index of array.
javascript :
function getButtonInfo() {
var jam = [7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22];
var lap = ['Lapangan A','Lapangan B','Lapangan Batminton'];
var lapId = ['lapA','lapB','lapBat'];
for (var j = 0; j < lap.length; j++){
for (var i = 0;i < jam.length; i++){
var lapIdFix = jam[i]+lapId[j];
var lapId2 = jam[i]+lap[j];
var lap1 = lap[j];
if(jam[i] < 10){
var jamFix = '0'+jam[i]+':00:00';
}else{
var jamFix = jam[i]+':00:00';
}
$.ajax({
type: "POST",
url:'get-button-avail-ajax.php',
data: {
date: document.getElementById('tgllapA').value,
time: jamFix,
lapangan: lap[j]
},
complete: function (response) {
if(response.responseText != "0"){
document.getElementById(lapIdFix).disabled = true;
$('#output').html(response.responseText );
$('#output1').html(lapIdFix);
$('#output2').html(lapId2);
}else{
$('#output3').html(response.responseText);
}
//$('#output').html(response.responseText);*
},
error: function () {
$('#output').html('ERROR!');
},
});
}
}
return false;
}
PHP File:
<?php
ob_start();
$error=""; // Variable To Store Error Message
$connection = mysqli_connect(/*credential*/);
$tgl = $_POST['date'];
$time = $_POST['time'];
$lap = $_POST['lapangan'];
//Query
$query = mysqli_query($connection, "SELECT * FROM lapangan_book WHERE tanggal='$tgl' and jam='$time' and lapangan='$lap'");
$rows = mysqli_num_rows($query);
$data = mysqli_fetch_array($query);
if($rows > 0){
echo $data['lapangan'];
}else{
echo "0";
}
?>
The output should be
Lapangan A
22lapA
22Lapangan A
But keep showing
Lapangan A
22lapBat
22Lapangan Batminton
Yes, this is happening because of the Asyncroniouse behavior of ajax. There is two tricks you have to send asynchronous request by async: false or you have to call the recursive function after success response from ajax request.
Trick 1- Pass option aysnc: false in ajax request, but some browser will throws warning in synchronous request of ajax
$.ajax({
type: "POST",
url:'get-button-avail-ajax.php',
async:false,
data: {
date: document.getElementById('tgllapA').value,
time: jamFix,
lapangan: lap[j]
},
complete: function (response) {
if(response.responseText != "0"){
document.getElementById(lapIdFix).disabled = true;
$('#output').html(response.responseText );
$('#output1').html(lapIdFix);
$('#output2').html(lapId2);
}else{
$('#output3').html(response.responseText);
}
//$('#output').html(response.responseText);*
},
error: function () {
$('#output').html('ERROR!');
},
});
}
Trick 2: Recursive function, this is most accurate way of calling
function getButtonInfo() {
var jam = [7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22];
var lap = ['Lapangan A','Lapangan B','Lapangan Batminton'];
var lapId = ['lapA','lapB','lapBat'];
var i=0;
var j=0;
var ajaxCall= function(){
var lapIdFix = jam[i]+lapId[j];
var lapId2 = jam[i]+lap[j];
var lap1 = lap[j];
if(jam[i] < 10){
var jamFix = '0'+jam[i]+':00:00';
}else{
var jamFix = jam[i]+':00:00';
}
$.ajax({
type: "POST",
url:'get-button-avail-ajax.php',
async:false,
data: {
date: document.getElementById('tgllapA').value,
time: jamFix,
lapangan: lap[j]
},
complete: function (response) {
if(response.responseText != "0"){
document.getElementById(lapIdFix).disabled = true;
$('#output').html(response.responseText );
$('#output1').html(lapIdFix);
$('#output2').html(lapId2);
}else{
$('#output3').html(response.responseText);
}
//$('#output').html(response.responseText);*
var recursiveCall=true;
i=i+1;
if(i>=jam.length){
j=j+1;
if(j>=lap.length) recursiveCall= false;
else i=0;
}
if(recursiveCall===true)
{
ajaxCall();
}
},
error: function () {
$('#output').html('ERROR!');
},
});
}
ajaxCall();
return false;
}
I have written code for your understanding might be your have to made come modification in this code

Send blob image to php

I've created a dynamic upload and I want to send each blob to server after the images are cropped.
The problem is that it's sent only the last append and I don't know why.
var g = 0;
for(var j = 1;j <= boxno;j++) //boxno = 4 pics (I can have as much as I want)
{
input = $("#input"+j);
if(input.val().length !== 0)//check if input has any values
{
pcanvas = $("#pcanvas"+j)[0];
context = pcanvas.getContext("2d");
formData = new FormData($(this)[0]);
var blob = dataURLtoBlob(pcanvas.toDataURL('image/png'));
formData.append("pcanvas_"+g+"[]", blob);
g++;
}
}
var info = {
userid:userId,
username:userName,
picNr: g
}
formData.append("info[]", info["userid"]);
formData.append("info[]", info["username"]);
formData.append("info[]", info["picNr"]);
$.ajax({
url: "/send.php",
type: "POST",
data: formData,
contentType: false,
cache: false,
processData: false,
success: function(data) {
console.log(data);
},
error: function(data) {
console.log("error");
},
complete: function(data) {}
});
function dataURLtoBlob(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], {
type: contentType
});
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {
type: contentType
});
}
Now if I send using this method is sent only "pcanvas3", the last loop. But If I put $.ajax inside the loop is working, but I don't want this, because I want to add into my db and is adding 4 times the same results (also I create new folder for a specific upload, so if I add inside the loop $.ajax it creates 4 folders)
Here is my php.
$id = $_POST['info'][0];
$username = $_POST['info'][1];
$picNr = $_POST['info'][2];
$shuffledid = str_shuffle($id);
$uniqueid = $id.$shuffledid;
$path = $_SERVER['DOCUMENT_ROOT'].'/_user/_tests/en/'.$uniqueid;
if(!file_exists($path))
{
mkdir($path,0755);
}
for($g = 0; $g <= $picNr; $g++)
{
$virtualbg = imagecreatetruecolor(400,410);
$tmp_file = $_FILES['pcanvas_'.$g]['tmp_name'][0];
$pic = imagecreatefrompng($tmp_file);
list($width,$height,$type) = getimagesize($tmp_file);
imagecopyresampled($virtualbg,$pic, 0,0,0,0, 400,410,$width,$height);
imagejpeg($virtualbg,$path.'/pic_'.$g.'.jpg');
imagedestroy($pic);
imagedestroy($virtualbg);
}
As you can see I'm passing through each "pcanvas_0,1,2,3,4" but only the last one it gets the tmp_files.
What I'm doing it wrong? I think the problem is on my append. I've tried to append something else to the formData("pcanvas.. and it works but my blob is not appended.
Thank you!

Updating varibles and running functions using setTimeout

I'm trying to send a drone a new set of coordinates every 1/2 of a second. Right now, it's not working the way I planned on it working (aka it's not working at all). I have 90 different Lat, Long, and Alt coordinates all predetermined inside my .js file. They are listed like this-
setTimeout(function () {long_in=-74.61122515230907;lat_in=41.05861743700108;alt_in=10}, 5000);
setTimeout(function () {long_in=-74.61124258212661;lat_in=41.05864962647036;alt_in=10}, 10000);
setTimeout(function () {long_in=-74.61125021662482;lat_in=41.05867214783328;alt_in=10}, 15000);
and so on...
Then they will need to pass thru this function -
if (coordinate == "GPS") {
console.log("GPS go");
lat_out = lat_in;
long_out = long_in;
alt_out = alt_in;
console.log(lat_out, long_out, alt_out)
}
And finally it will send this command to the drone-
var msgdata = {};
msgdata["twist"] = {};
msgdata.twist["twist"] = {};
msgdata.twist.twist["linear"] = {};
msgdata.twist.twist.linear["x"] = lat_out;
msgdata.twist.twist.linear["y"] = long_out;
msgdata.twist.twist.linear["z"] = alt_out;
msgdata.twist.twist["angular"] = {};
msgdata.twist.twist.angular["z"] = 1.00;
msgdata["tolerance"] = 2.00;
msgdata["async"] = true;
msgdata["relative"] = false;
msgdata["yaw_valid"] = true;
msgdata["body_frame"] = false;
$.ajax({
type: "POST",
dataType: "json",
data: JSON.stringify(msgdata),
url: "http://" + ip + "/ros/" + namespace + "/navigation/position_set",
success: function (data) {
console.log(data, "Coordinates sent", lat_out,long_out,alt_out);
}
});
I have defined all of my variables prior to this code globally. All of the commands work perfectly fine, I just can't get them to all refresh every 1/2 of a second. Do I need to have all of these commands inside every setTimeout or something? Thanks for the help.
Yes you need to make the call again and again. You could wrap it in a function and make the call happen again and again from the setTimeout.
I have created a callback chain to guarantee order of execution based on #Liam's recommendation and the comments discussion.
setTimeout(function() {
long_in = -74.61122515230907;
lat_in = 41.05861743700108;
alt_in = 10;
prepSignal(long_in, lat_in, alt_in, function() {
setTimeout(function() {
long_in = -74.61124258212661;
lat_in = 41.05864962647036;
alt_in = 10;
prepSignal(long_in, lat_in, alt_in, function() {
setTimeout(function() {
long_in = -74.61125021662482;
lat_in = 41.05867214783328;
alt_in = 10;
prepSignal(long_in, lat_in, alt_in);
}, 5000);
});
}, 5000);
});
}, 5000);
var coordinate = "GPS";
function prepSignal(long_in, lat_in, alt_in, callback) {
if (coordinate == "GPS") {
console.log("GPS go");
lat_out = lat_in;
long_out = long_in;
alt_out = alt_in;
console.log(lat_out, long_out, alt_out, callback);
sendSignal(long_in, lat_in, alt_in, callback);
}
function sendSignal(long_in, lat_in, alt_in, cb) {
var msgdata = {};
msgdata["twist"] = {};
msgdata.twist["twist"] = {};
msgdata.twist.twist["linear"] = {};
msgdata.twist.twist.linear["x"] = lat_out;
msgdata.twist.twist.linear["y"] = long_out;
msgdata.twist.twist.linear["z"] = alt_out;
msgdata.twist.twist["angular"] = {};
msgdata.twist.twist.angular["z"] = 1.00;
msgdata["tolerance"] = 2.00;
msgdata["async"] = true;
msgdata["relative"] = false;
msgdata["yaw_valid"] = true;
msgdata["body_frame"] = false;
$.ajax({
type: "POST",
dataType: "json",
data: JSON.stringify(msgdata),
url: "http://" + ip + "/ros/" + namespace + "/navigation/position_set",
success: function(data) {
console.log(data, "Coordinates sent", lat_out, long_out, alt_out);
if(cb && typeof cb == "function") {
cb();
}
}
});
}
}
You have to run recalculation inside setTimeout after you set a value.

How to get selected file list in javascript?

I am trying to create a file upload with progress-bar with the help of HTML5. trying to create multiple file-upload. Below is my code. Inside handleFiles function i have one alert statement and its returning 'undefined'. Can anyone help me here...
$('#photoimg').change(function()
{
handleFiles(this.files); alert('got it');
var $fileUpload = $("#photoimg");
if (parseInt($fileUpload.get(0).files.length)>$('#galCnt').val())
{
alert("Maximum of 5 images allowed to upload. Only "+$('#galCnt').val()+" left");
return false;
}
//var formData = new FormData($('#imageform')[0]);
fd = collectFormData();
// Attach the files.
for (var i = 0, ie = PENDING_FILES.length; i < ie; i++) {
// Collect the other form data.
fd.append("file", PENDING_FILES[i]);
}
// Inform the back-end that we're doing this over ajax.
fd.append("__ajax", "true");
$("#imageloadstatus").show();
//$("#imageloadbutton").hide();
var $progressBar = $("#progress-bar");
$progressBar.css({"width": "0%"});
var xhr = $.ajax({
xhr:function() {
var xhrobj = $.ajaxSettings.xhr();
if (xhrobj.upload) {
xhrobj.upload.addEventListener("progress", function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
// Set the progress bar.
$progressBar.css({"width": percent + "%"});
$progressBar.text(percent + "%");
$("#loaded_n_total").innerHTML = "Uploaded "+event.loaded+" bytes of "+event.total;
}, false)
}
return xhrobj;
},
url: SITE_URL+'/index/ajax',
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
processData: false,
success: function (returndata) {
$progressBar.css({"width": "100%"});
$("#imageloadstatus").hide();
$('#preview').html(returndata);
}
});
});
var PENDING_FILES = [];
function collectFormData() {
// Go through all the form fields and collect their names/values.
var fd = new FormData();
$("#imageform :input").each(function() {
var $this = $(this);
var name = $this.attr("name");
var type = $this.attr("type") || "";
var value = $this.val();
// No name = no care.
if (name === undefined) {
return;
}
// Skip the file upload box for now.
if (type === "file") {
return;
}
// Checkboxes? Only add their value if they're checked.
if (type === "checkbox" || type === "radio") {
if (!$this.is(":checked")) {
return;
}
}
fd.append(name, value);
});
return fd;
}
function handleFiles(files) {
// Add them to the pending files list.
for (var i = 1; i <= files.length; i++)
{
alert(files[i]);
PENDING_FILES.push(files[i]);
}
}

Loop through XML files jQuery

I am a bit stuck with the following problem.
I have several XML files tagged by an ID (every XML is id'd by a value). I am now trying to loop through these files and output its contents to HTML.
However it starts the loop before it does the call back
Loop0
Loop1
Loop2
Callback0
Callback1
Callback2
I would need
Loop0
Callback0
Loop1
Callback1
As I need to control the results at some point.
var allContent=["xmlfile1","xmlfile2","xmlfile3","xmlfile4"];
var totalSearch = 0;
var countSearch = 0;
function doSearch() {
var oldContentID = contentID;
for (iSearch=0;iSearch<allContent.length;iSearch++) {
totalSearch = totalSearch + countSearch;
contentID = allContent[iSearch];
defineContent();
getXML();
}
}
function getXML() {
$.ajax({
type: "GET",
url: langFile,
dataType: "xml",
beforeSend: function(){
$('#results-list').empty();
$('#results-list').hide();
$('#loading').addClass('loading');
},
success: function(xml) {
var totalElements;
var intSearch = 0;
totalSearch = totalSearch + countSearch;
countSearch = 0;
var searchText = $('#text').val().toLowerCase();
totalElements = $(xml).find('news').length;
while (intSearch < totalElements) {
oFeed = $(xml).find('news:eq('+intSearch+')');
var headline = oFeed.find('headline').text();
var newsText = oFeed.find('detail').text();
var section = oFeed.find('section').text();
var category = oFeed.attr('category');
var stripEnters = newsText.match(/\r?\n|\r/gi);
if (stripEnters != null) {
for (var s = 0; s < stripEnters.length ; s++ ){
newsText = newsText.replace(stripEnters[s],'');
}
}
var newsText2 = $.htmlClean(newsText, {format:true});
var newsText3 = $(newsText2)
var newsText4 = $(newsText3).text();
var newsText5 = newsText4.replace( /\W/gi, "" );
if (section.toLowerCase() == "news" || section.toLowerCase() == "featured") {
if (headline.toLowerCase().indexOf(searchText) >= 0) {
$('<dt></dt>').html(headline).appendTo('#results-list');
$('<dd></dd>').html(newsText).appendTo('#results-list');
countSearch++;
}//end if
else if (newsText5.toLowerCase().indexOf(searchText) >= 0) {
$('<dt></dt>').html(headline).appendTo('#results-list');
$('<dd></dd>').html(newsText).appendTo('#results-list');
countSearch++;
}
}
intSearch++;
}
}
});
}
At the end of the call backs I need to run the following, however it now executes this function before it finishes all call backs.
function displayResults() {
if (totalSearch == 0)
{
alert("No results found");
$('#loading').removeClass('loading');
$('#main').fadeIn(1000);
}
else {
dynamicFaq();
$('<p></p>').html(totalSearch + ' Results found').prependTo('#results-list');
$('#results-list').fadeIn(1000);
$('#loading').removeClass('loading');
}
}
If I understood you correctly, you want to load 1 xml file, loop, and then start to load the next xml file. If so, here is a little pseudo code:
function doSearch(int xmlFileIterator){
if (xmlFileIterator < allContent.length) {
...
contentID = allContent[xmlFileIterator];
...
getXml(xmlFileIterator);
} else {
//no more xml files left
displayResults();
}
}
function getXml(int xmlFileIterator) {
...
success: function() {
...
doSearch(++xmlFileIterator);
}
}
The first call is doSearch(0) which loads the first xml file. After the file is loaded and the loop is done (in success) you can call the doSearch function again with a higher number (iterator).
I see your AJAX call is Asynchronous. Try using
....
type: "GET",
url: langFile,
async: false,
dataType: "xml",
.....
Maintain a ajax queue so thos ajax call will be done one by one. plus maintain a global variable searchedCount which will maintain how main xml are proccessed.
In complete callback of ajax check for the searchedCount and call displayResults function .
var allContent = ["xmlfile1", "xmlfile2", "xmlfile3", "xmlfile4"];
var totalSearch = 0;
var countSearch = 0;
var searchedCount = 0;
var ajaxQueue = $({});
$.ajaxQueue = function (ajaxOpts) {
// Hold the original complete function.
var oldComplete = ajaxOpts.complete;
// Queue our ajax request.
ajaxQueue.queue(function (next) {
// Create a complete callback to fire the next event in the queue.
ajaxOpts.complete = function () {
// Fire the original complete if it was there.
if (oldComplete) {
oldComplete.apply(this, arguments);
}
// Run the next query in the queue.
next();
};
// Run the query.
$.ajax(ajaxOpts);
});
};
function doSearch() {
var oldContentID = contentID;
searchedCount = 0;
for (iSearch = 0; iSearch < allContent.length; iSearch++) {
totalSearch = totalSearch + countSearch;
contentID = allContent[iSearch];
defineContent();
searchedCount++;
getXML();
}
}
function getXML() {
$.ajaxQueue({
type: "GET",
url: langFile,
dataType: "xml",
beforeSend: function () {
$('#results-list').empty();
$('#results-list').hide();
$('#loading').addClass('loading');
},
success: function (xml) {
//your code
},
complete: function () {
if (searchedCount == allContent.length) {
displayResults()
}
}
});
}

Categories

Resources