Find resultant of two asynchronous ajax request in xhr onprogress - javascript

I am trying to find images in ajax request response text and fetch the src url for using in another ajax request.
I need to know progress of loading each image and show the resultant of this progress in my progress bar.
But as you can see if image1 loaded 10%;
and image2 20%.
My result decreases from 20% to 10% .
My progress bar goes backward and then goes forward.
Any help?
or is this a good solution?
parseResult: function(result, navNumber) {
var self = this;
var imagesMatter = $(result).find('img');
var imagesLength = imagesMatter.length;
// if there is any image in ajax request then fetch imgs using ajax for show progress bar
if (imagesLength >= 1) {
var i = 0,
complete = 0,
temp = 1;
navigation.progress.fadeIn(50);
imagesMatter.each(function() {
var $this = $(this);
var URL = $this.attr('src');
$.ajax({
url: URL,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = parseFloat(evt.loaded / evt.total).toFixed(1);
temp = complete + (percentComplete / imagesLength);
console.log(parseInt(temp * 100) + '%');
navigation.progress.html(parseInt(temp * 100) + '%');
}
}, false);
return xhr;
},
complete: function() {
complete = temp;
i++;
if (i == imagesLength) {
self.closeLoading(navNumber);
}
}
});
});
} else {
return;
}
}

Here I have removed complete variable of yours, as I can' understand what is the purpose of it, and added a local variable lastPercent for each request, which will remember it's last progress percent for the perticular image request, so on new update we will add new percent and remove old percents... I hope this logic is clear to you...
parseResult: function(result, navNumber) {
var self = this;
var showPercent;
var imagesMatter = $(result).find('img');
var imagesLength = imagesMatter.length;
// if there is any image in ajax request then fetch imgs using ajax for show progress bar
if (imagesLength >= 1) {
var i = 0,
temp = 1;
navigation.progress.fadeIn(50);
imagesMatter.each(function() {
var $this = $(this);
var URL = $this.attr('src');
var lastPercent = 0;
$.ajax({
url: URL,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = parseFloat(evt.loaded / evt.total).toFixed(1);
temp = temp + (percentComplete / imagesLength) - lastPercent;
lastPercent = (percentComplete / imagesLength);
showPercent = temp/imagesLength;
console.log(parseInt(showPercent * 100) + '%');
navigation.progress.html(parseInt(showPercent * 100) + '%');
}
}, false);
return xhr;
},
complete: function() {
i++;
if (i == imagesLength) {
self.closeLoading(navNumber);
}
}
});
});
} else {
return;
}
}

Related

Sending two files in a queue

Hey I have a problem with sending two files in a queque. I don't have any idea how to do that when I select 2 files, 2 were uploaded at once, and the next 2 were waiting in queue. Now when I select 4 files, 2 are sent and the next two will not send. Please look in my code. Maybe you have an idea. What I must to do that make it work in function induction ?
(function() {
var imageType = /image.*/;
function uploadFile(file, percent_info, p_bar, licznik) {
var url = "server/index.php";
if (file[licznik].type.match(imageType)) {
var xhr = new XMLHttpRequest();
var fd = new FormData();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
if (percentLoaded < 100) {
percent_info[licznik].style.width = percentLoaded + "%";
}
}
});
xhr.upload.addEventListener("load", function(e) {
var percentLoaded = Math.round((e.loaded / e.total) * 100);
percent_info[licznik].style.width = percentLoaded + "%";
});
function ready() {
return function() {
if (xhr.readyState == 4 && xhr.status == 200) {
p_bar[licznik].classList.add('trans_completed');
if (licznik < file.length){
licznik++;
}
}
};
}
xhr.onreadystatechange = ready();
xhr.open("POST", url, true);
fd.append('uploaded_file', file[licznik]);
xhr.send(fd);
}
};
var uploadfiles = document.querySelector('#file-upload');
uploadfiles.addEventListener('change', function() {
var files = this.files;
var percent_info = document.querySelectorAll('.progress_bar:not(.trans_completed) .percent');
var p_bar = document.querySelectorAll('.progress_bar:not(.trans_completed)');
/* --- Upload files to server loop --- */
(function induction(files, percent_info, p_bar) {
counter_file = 0;
counter_file_2 = 1;
function caller() {
uploadFile(files, percent_info, p_bar, counter_file);
uploadFile(files, percent_info, p_bar, counter_file_2);
}
caller();
})(files, percent_info, p_bar);
});
})();

Ajax loading bar function

I know there are a few post about this but they dont cover what i need to achieve.
I'm trying to get the youtubelike loading bar to work properly.
And i found this :
var data = [];
for (var i = 0; i < 100000; i++) {
var tmp = [];
for (var i = 0; i < 100000; i++) {
tmp[i] = 'hue';
}
data[i] = tmp;
};
xhr: function () {
var xhr = new window.XMLHttpRequest();
var percentComplete = 0; <--------------------------added this
$('.progress').removeClass('hide');<----------------and this
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
$('.progress').css({
width: percentComplete * 100 + '%'
});
if (percentComplete === 1) {
$('.progress').addClass('hide');
}
}
}, false);
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
$('.progress').css({
width: percentComplete * 100 + '%'
});
}
}, false);
return xhr;
}
I have added 2 lines because it would only work once as the hidden value was not being removed after the completion. Also put the width back to 0. I also like the fact that it seams to be calculating the real percentage of the event.
This is working great. Howerver, i want to turn this into a function that can be called for all my ajax call like this:
$(document).ready(function () {
$("a").on("click", function (event) {
event.preventDefault();
var id = ($(this).attr("id"));
var container = ($(this).attr("data-container"));
var link = ($(this).attr("href"));
var text = ($(this).text());
var html = ($(this).html());
MY_LOADING_BAR_FUNCTION();<-----------------------------------Here i guess?
$.ajax({
url: 'ajax-php.php',
type: 'post',
data: { 'action': 'click', 'id': id, 'text': text, 'link': link, 'html': html },
success: function (data, status) {
if (container == '#formbox') {
$("#screen").addClass("visible");
}
$(container).html(data);
},
error: function (xhr, desc, err) {
console.log(xhr);
console.log("Details: " + desc + "\nError:" + err);
}
}); // end ajax call
}); // end on click
}); // en document ready
But i also ran across the Ajax setup that looks like this.
$.ajaxSetup({
beforeSend: function() {
},
complete : function() {
}
});
Right now i got it to work by putting the entire code of the xhr: function () inside my ajax call. But i dont want to do it every time.
So these are the 2 options i have found that could work but i cant get them to work the way i want. I try to make a MY_LOADING_BAR_FUNCTION() but i'm getting a deprecated error.
Can anyone tell me how to make this work please.
Thank you everyone!
It's late to reply, but its worth to share some knowledge, so others may get help from it.
You can extend jQuery AJAX XHR object as below.
jQuery.ajaxSettings.xhr = function ()
{
var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with upload progress
console.log('percent uploaded: ' + (percentComplete * 100));
}
}, false);
//Download progress
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
console.log('percent downloaded: ' + (percentComplete * 100));
}
}, false);
return xhr;
}

Javascript - progress bar with muliple images

I want to preload a bunch of images and show the progress bar in the same time.
At the moment the code works only with 1 image, here is it:
$progress = document.querySelector('#progress');
var url = 'https://placekitten.com/g/2000/2000';
var request = new XMLHttpRequest();
request.onprogress = onProgress;
request.onload = onComplete;
request.onerror = onError;
function onProgress(event) {
if (!event.lengthComputable) {
return;
}
var loaded = event.loaded;
var total = event.total;
var progress = (loaded / total).toFixed(2);
$progress.textContent = 'Loading... ' + parseInt(progress * 100) + ' %';
console.log(progress);
}
function onComplete(event) {
var $img = document.createElement('img');
$img.setAttribute('src', url);
$progress.appendChild($img);
console.log('complete', url);
}
function onError(event) {
console.log('error');
}
$progress.addEventListener('click', function() {
request.open('GET', url, true);
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send(null);
});
<div id="progress">Click me to load</div>
And here is the jsfiddle to test the code out: https://jsfiddle.net/q5d0osLr/
How can I make it work with more than one image?
Use an array to store each progress and create a function to load image and record the necessary information for you.
var $progress = document.querySelector('#progress');
var url = 'https://placekitten.com/g/';
var urls =
['https://i.imgur.com/7raUYR2.jpg', 'https://i.imgur.com/i8GSA1b.jpg', 'https://i.imgur.com/jGkaxEZ.jpg',
'http://i.imgur.com/cuS5DDv.jpg', 'https://i.imgur.com/bl5DOR0.jpg', 'http://i.imgur.com/TuFu2lK.jpg',
'https://i.imgur.com/qbwarWi.jpg', 'https://i.imgur.com/hJ9Ylph.gif', 'https://i.imgur.com/8KLbDxe.jpg',
'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Pleiades_large.jpg/1024px-Pleiades_large.jpg',
];
// Store all progress.
var allProgress = [];
var loadImage = function(url) {
// Get current index.
var idx = allProgress.length;
// Push a progress in array.
allProgress.push(0.0);
var onProgress = function(evt) {
if (!evt.lengthComputable) {
return;
}
var loaded = evt.loaded;
var total = evt.total;
var progress = (loaded / total);
allProgress[idx] = progress;
// Calculate the progress by sum then divide.
var sum = allProgress.reduce(function(sum, val) {
return sum + val;
});
sum /= allProgress.length;
sum = sum.toFixed(2);
$progress.textContent = 'Loading... ' + parseInt(sum * 100) + ' %';
console.log(progress, idx);
};
var onComplete = function(evt) {
var $img = document.createElement('img');
$img.setAttribute('src', url);
document.body.appendChild($img);
console.log('complete', url);
};
var onError = function(evt) {
// You may have to do something with progress.
console.log('error');
};
// Move the request in function. So each of them is independent.
var request = new XMLHttpRequest();
request.onprogress = onProgress;
request.onload = onComplete;
request.onerror = onError;
request.open('GET', url, true);
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send(null);
};
$progress.addEventListener('click', function() {
urls.forEach(function(url) {
loadImage(url);
});
});
img {
width: 100px;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="progress">Click me to load</div>

Having trouble with program flow - juggling between AJAX callbacks and rendering PIXI JS

I'm having trouble making my js script flow smoothly. It's a script that receives and sends mouse co-ordinates and draws them.
Here it is:
//Initialize PIXI
var stage = new PIXI.Stage(0x000000);
var renderer = new PIXI.WebGLRenderer(1600, 900);
document.body.appendChild(renderer.view);
//requestAnimFrame(animate);
function animate() {
console.log("Draw.");
requestAnimFrame(animate);
renderer.render(stage);
}
//Function for receiving data.
indx = 0;
var makeRequest = function(){
var ajaxFunction = function(){
if(ajaxRequest.readyState == 4){
var pointsStr = ajaxRequest.responseText.split("C"); //The co-ordinates are received in this form: "pointCpointCpointCpoint...pointCindex"
indx = parseInt(pointsStr[pointsStr.length - 1]);
for (i = 0; i < pointsStr.length - 1; i++) {
if(pointsStr[i] != ""){
var points = pointsStr[i].split(",");
mouseX = parseInt(points[0]);
mouseY = parseInt(points[1]);
var graphics = new PIXI.Graphics(); //Why create new graphics every time? PixiJS bugs out if I don't. Probably also something to do with the flow.
graphics.lineStyle(1, 0xFFFFFF);
stage.addChild(graphics);
graphics.drawRect(mouseX,mouseY,1,1);
renderer.render(stage);
console.log("Received.")
}
}
}
}
var ajaxRequest = new XMLHttpRequest();
ajaxRequest.onreadystatechange = ajaxFunction;
ajaxRequest.open("GET", "http://127.0.0.1/receiveData/0=" + indx, true);
ajaxRequest.send();
}
//Function for sending data.
var sendRequest = function(arr){
var t = ""
for (var i = 0; i < arr.length; i++) {
t += arr[i].x.toString() + "," + arr[i].y.toString() + "C";
}
t = t.slice(0,-1);
var ajaxRequest = new XMLHttpRequest();
ajaxRequest.open("POST", "http://127.0.0.1/sendData/" + t, true);
ajaxRequest.send();
console.log("Send.")
}
pos = {
x: 0,
y: 0
}
var mouseRecording = new Array();
document.addEventListener('mousemove', function(e){
var p = pos;
p.x = e.clientX || e.pageX;
p.y = e.clientY || e.pageY;
mouseRecording.push(pos);
console.log("" + p.x + "," + p.y)
}, false);
var interval = setInterval(function(){
console.log("Make Request.");
sendRequest(mouseRecording);
makeRequest();
}, 100);
Basically, the problem is that the flow is really inconsistent.
For example it'd just POST and GET for 10 seconds with no callback being run, but then suddenly 200 requests would run subsequently, and then maybe once in a blue moon the screen would render etc.
What is the correct way here to make the program flow adequately?
A few notes on function naming and responsibilities: 1. If your function has a really generic short name and a comment right above it that says something different, then get rid of the comment and rename your function. 2. Your function should only do what it says it does it does, and nothing more. 3. Your function should not modify its parent scope. Side effects make debugging difficult.
That said, let's start by breaking this out into a whole bunch of tiny functions that do so little, they can't possibly do anything wrong. And named so that they don't do anything else.
//Initialize PIXI
var stage = new PIXI.Stage(0x000000);
var renderer = new PIXI.WebGLRenderer(1600, 900);
document.body.appendChild(renderer.view);
function httpRequest(method, url, success, fail) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 ) {
if(xmlhttp.status == 200){
success(xmlhttp.responseText);
}
else {
fail();
}
}
}
xmlhttp.open(method, url, true);
xmlhttp.send();
}
function getRequest(url, success, fail) {
httpRequest('GET', url, success, fail);
}
function postRequest(url, success, fail) {
httpRequest('POST', url, success, fail);
}
function buildDataStringFromCoords(coords) {
return coords.map(function(coord) {
return coord.x.toString() + ',' + coord.y.toString();
}).join('C');
}
function buildCoordsFromDataString(dataString) {
return dataString.split('C').map(function(coordString) {
var points = coordString.split(',');
return {x:+points[0], y:+points[1]};
});
}
function renderCoords(coords) {
var graphics = new PIXI.Graphics(); //Why create new graphics every time? PixiJS bugs out if I don't. Probably also something to do with the flow.
graphics.lineStyle(1, 0xFFFFFF);
stage.addChild(graphics);
graphics.drawRect(coords.x, coords.y, 1, 1);
renderer.render(stage);
}
function requestCoords(indx, success, fail) {
var url = 'http://127.0.0.1/receiveData/0=' + indx;
getRequest(
url,
function(response) {
var coords = buildCoordsFromDataString(response);
success(coords);
},
function() {
fail();
}
);
}
var sendCoords = function(coords, success, fail) {
var url = 'http://127.0.0.1/sendData/' + buildDataStringFromCoords(coords);
postRequest(
url,
function() {
success();
},
function() {
fail();
}
);
}
pos = {
x: 0,
y: 0
};
var mouseRecording = new Array();
document.addEventListener('mousemove', function(e){
var p = pos;
p.x = e.clientX || e.pageX;
p.y = e.clientY || e.pageY;
mouseRecording.push(pos);
console.log('Mouse moved', p.x, p.y);
}, false);
var interval = setInterval(function(){
console.log("Make Request.");
sendCoords(
mouseRecording,
function() {
console.log('Successfully sent coords', mouseRecording);
},
function() {
console.log('Failed to send coords', mouseRecording);
}
);
requestCoords(
indx,
function(coords) {
console.log('Successfully fetched coords', coords);
coords.forEach(function(coord) {
renderCoords(coord);
});
console.log('Rendered coords', indx);
},
function() {
console.log('Failed to get coords', indx);
}
);
}, 100);
This now lets us write some tests to prove that each part is "correct", so you don't have to step through the entire big thing every time something goes wrong. For example:
function testBuildDataStringFromCoords() {
return buildDataStringFromCoords([{x:123,y:456},{x:987,y:654}]) === '123,456C987,654';
}
This might not completely fix the issues you have, but I hope it makes your life easier and will make the issue more transparent.

Multiple onprogress event handlers from xhr in loop

I'm currently trying to build an ajax image uploader and I have it working except for one important part.
For each separate file I upload I would like to update a progress bar for the file. Currently it only updates the last files progress bar.
$("#upload-btn").click(function() {
console.log("Click");
for (var i = 0; i < files.length; i++) {
var fd = new FormData();
fd.append("file", files[i]);
fd.append("__RequestVerificationToken", $("input[name='__RequestVerificationToken']").val());
var xhr = new XMLHttpRequest();
xhr.open('POST', "#Url.Action("AjaxUpload")", true);
var filename = files[i].name;
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete + '% uploaded');
var progressbar = $('a[data-name="' + files[i].name + '"]').siblings(".progress").find(".progress-bar");
progressbar.css("width", percentComplete + "%");
}
};
xhr.onload = function () {
console.log(this.status);
if (this.status == 200) {
var resp = JSON.parse(this.response);
console.log('Server got:', resp);
};
};
xhr.send(fd);
}
});
As you may have guessed from the code, I'm pretty terrible at javascript... Any help is greatly appreciated.
You need to scope your file name in the progress callback, currently it will only use the last value of i. Replace where you set your onprogress handler with this code.
(function(filename) {
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete + '% uploaded');
var progressbar = $('a[data-name="' + filename + '"]').siblings(".progress").find(".progress-bar");
progressbar.css("width", percentComplete + "%");
}
};
})(files[i].name);
You can do something like this. Set the additional parameters of xhr.upload
// Set custom properties
xhr.upload.targetFileName = fileName;
and then access it in progress handler like this
xhr.upload.onprogress = function (e) {
// Access custom properties.
var fileName = e.target.targetFileName;
}
More details here: https://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/ view-source:http://mozilla.pettay.fi/xhr_upload/xhr_file_upload_demo_with_speed.html

Categories

Resources