Okay, it might be a simple question, but so far I didn't find anything helpful by searching, so I am giving it a try here.
I am using plain old javascript/jquery on asp.net core on some project I am working on.
I am currently performing some actions on some employees in a foreach loop.
For each employee I am calling synchronously via ajax an API.
What I want is the UI to be updated, showing the current employee being processed in a progress bar.
While on debug, the process seems to work fine, but during normal process, it seems that the UI thread is not updated, only after all the work has been done. As such, as soon as I start processing the employees, the screen is stuck and closes after the work has been done. No progress bar is shown.
I only managed to show the progress animation and the first employee using the below trick
$('#applyYes').click(function (e) {
e.preventDefault();
var year = $('#yearCombo').val();
$('#applyInfo').hide();
$('#applyLoad').show();
$('#applyAction').prop('innerText', 'Calculating...');
setTimeout(function () {
var employeeIDs = multipleEmployees_Array();
for (var i = 1; i <= employeeIDs.length; i++) {
employeeID = employeeIDs[i - 1];
applyAmount(employeeID, year); //1. Updates progress bar 2. Ajax sync call
}
}, 0);
})
As far as I understand the e.preventDefault seems to move the timeout function being processed after UI thread finishes.
What is the optimal way of achieving what I want?
PS: No external libraries if possible. I am working on an third-party platform, that makes it difficult to add external libraries (policies, permissions etc.)
Synchronous HTTP requests are deprecated for precisely this reason. Don't use them.
Use Asynchronous requests instead.
If you want to run them sequentially then either:
Trigger i+1 in i's success function or
Use a Promise based API and await the results
Related
I have an api in django and I am calling it from react front end, the thing is the api have to be called infinitely and in every request from react, there is always new image came from request's response.The response is coming in a good speed but the speed of the reactjs displaying the images is really slow, I am displaying the images without reloading the whole component and I want to display it without reloading.
runInfinite=()=>{
axios.post('http://127.0.0.1:8000/faceapp/process_image/')
.then(res => {
this.setState({baseimage: res.data}, () => {
console.log(this.state.baseimage)
})
});
};
render() {
if (this.state.flag){
setInterval(()=> { this.runInfinite(); },1000);
}
return (
<div>
{this.state.baseimage?<img src={"data:image/png;base64," + this.state.baseimage}/>:<h1>Hello</h1>}
</div>
);
}
}
What can I do so React can display images in the same speed as the response is coming.
There is probably nothing that react can do in this case. You'll have to optimise the image and their dimensions as required on the page itself.
Like, You can start with checking the resolution needed.
E.g. There is no need to load an image of 4000*3000 in a placeholder of 400*300.
I can hardly imagine that React is too slow for rendering an image. Please validate where you're actual delay is coming from.
Other than that, you have a potential DoS issue.
Combining setInterval (never use setInterval) with an IO request (especially for processing data) is a recipe for error. What happens when your server takes more than 1000ms to respond? Answer: multiple requests start stacking up and slowing down the program to a hold. Might that be what's actually happening?
Avoid this behavior by
Initialing a request for a Promise or other callback.
When completed, run logic based on output.
Then reschedule request after all of this has been completed.
I have an angular service that makes an Web API call out to retrieve my search results. The problem I'm having is the angular controller & UI is set up in a way that allows the search to be called multiple times per second causing the service to be queued up. I tried resolving/defer the http call when a new one comes in but it doesnt seem like the best solution. I would rather queue up all the search calls I get within a certain time period and then only execute the last one. Any ideas on how I could do that?
timeout(function(){
var length = queue.length
var item = queue[length - 1];
queue.splice(0, length);
processItem(item);
} , <yourtime:number>)
keep adding your requests to the queue. and add the processing logic to the processItem function.
this might do the needful
*note - please consider this as a pseudo code. might have compilations errors
Alternatively you can just create a bool variable which is referred every time a request is about to be made and done make the request till its true. Somethign like this
function processItem(item){
if(process){
process = false;
//YOUR ACTUAL PROCESSING CODE
}
}
$timeout(function(){
process = true;
}, <yourtime in milli seconds>)
I am not too familiar with AJAX but I'm sure what I am trying to do is possible.
Basically I have a form with a text area, when the form is submitted the text area is made into an array with each new line being a value. Simple stuff, now my php then performs a database query on each array value. Also simple.
Now as the operation takes a while I want to make it into an AJAX call using jquery, and for every iteration on the array I want it to display the result back on my main page as well as displaying a progress bar.
So if my text area contains a list of 20,000 names and the query is to fetch the ages of these people, the ajax call would split the textarea into an array and iterate the array. For each iteration it should perform the query and send the result to my main page. So on my main page I will see a list that grows over time.
I hope I have explained this well enough, I just need advice on where to start/what to research. Any examples would be greatly appreciated.
Thanks!
As ajax is simply a request for data you cannot create a reliable loading bar easily.
However if you are doing loads of requests as you suggest in your question, "Which by the way is not the best idea".
You could do something like the code below. Again its pretty basic but will give your user a rough idea. I stuck it in a fidddle here for you http://jsfiddle.net/6dgAF/ its a basic example but should give you a jump off point.
function Status(data)
{
this.data = data;
this.size = this.data.length;
this.current = 0;
this.bar = $("#bar");
//Get width of each step of load
this.step = (this.bar.width() / this.size) ;
for(var i =0; i < this.size; i++){
this.getData(this.data[i]);
}
}
Status.prototype.getData = function(string){
//run your ajax here on each string and on success do this
//$.get( "ajax/test.html", function( string ) {
//this.current++;
//this.updateBar();
//});
this.current++;
this.updateBar();
}
Status.prototype.updateBar = function(){
//updates the bar with the current count * step width;
$("span",this.bar).width(this.step*this.current);
}
//Init object and put in dummy data
var status = new Status(new Array("string1","string2","string3","string4","string5","string6","string7","string8","string9","string10"));
An AJAX request is nothing else than requesting data from your server, just like any HTML page. The only difference is that you use Javascript, and don't feed the data to your browser as an HTML page, but use the data some way on your page.
One possible way to do the thing you want is the following:
Set an interval with the refresh rate, which calls a function getData
In getData you perform an AJAX request, which requests a piece of data from the server, which represents the current state. You might want to make sure the server only returns incremental updates, to avoid sending large amounts of data
Use the data on your front page, by displaying it in a friendly way to the user.
The main thing to keep in mind is that the server must save it's current state (the data which it has gathered with its queries), which it must return in the event of an AJAX request.
What you want is called XHR2 - personally I am using dojo
(dojo/request/xhr here)
However it should be possible with jQuery as well, search for jQuery XHR2 progress ...
I have an AngularJS application which perform
- 1 request to fetch the main user profile, that contains references to the user friends,
- and then 1 request per friend to retrieve the friend profile.
When we click on a friend's profile, we load this profile as the main profile.
I am in the RDF / semantic web world, so I can't model these interactions differently, this is not the point of the question.
This is an early version of the application I'm trying to build, that can help you understand what's my problem: http://sebastien.lorber.free.fr/addressbook/app/
The code looks like:
$scope.currentProfileUri = 'http://bblfish.net/people/henry/card#me';
$scope.$watch('currentProfileUri', function() {
console.debug("Change current profile uri called with " + $scope.currentProfileUri);
loadFullProfile($scope.currentProfileUri);
})
// called when we click on a user's friend
$scope.changeCurrentProfileUri = function changeCurrentProfileUri(uri) {
$scope.currentProfileUri = uri;
}
function loadFullProfile(subject) {
$scope.personPg = undefined;
// we don't want to capture the scope variable in the closure because there may be concurrency issues is multiple calls to loadFullProfile are done
var friendsPgArray = [];
$scope.friendPgs = friendsPgArray;
fetchPerson(subject).then(function(personPg) {
$scope.personPg = personPg
fetchFriends(personPg,function onFriendFound(relationshipPg) {
friendsPgArray.push(relationshipPg);
});
},function(error) {
console.error("Can't retrieve full profile at "+uri+" because of: "+error);
});
}
So the friends are appended to the UI as they come, when the http response is available in the promise.
The problem is that the function changeCurrentProfileUri can be called multiple times, and it is possible that it is called by while there are still pending requests to load the current users's friends.
What I'd like to know is if it's possible, on changeCurrentProfileUri call, to cancel the previous http requests that are still pending? Because I don't need them anymore since I'm trying to load another user profile.
These pending requests will fill an instance of friendsPgArray that is not in the scope anymore and won't be put in the scope, so it is just useless.
Using Java Futures, or frameworks like RxScala or RxJava, I've seen there's generally some kind of "cancel" or "unsubscribe" method which permits to de-register interest for a future result. Is it possible to do such a thing with Javascript? and with AngularJS?
Yes, it is! Please, see this section of angular $http service docs. Note timeout field in config object. It does, I think, exactly what you need. You may resolve this pormise, then request will be marked as cancelled and on error handler will be called. In error handler you may filter out this cases by there http status code - it will be equal to 0.
Here is fiddle demonstrating this
im making a wordpress plugin and i have a function where i import images, this is done with a $.each()-loop that calls a .load()-function every iteration. The load-function page the load-function calls is downloading the image and returns a number. The number is imported into a span-element. The source and destination Arrays is being imported from LI-elemnts of a hidden ULs.
this way the user sees a counter counting from zero up to the total number of images being imported. You can se my jQuery code below:
jQuery(document).ready(function($) {
$('#mrc_imp_img').click(function(){
var dstA = [];
var srcA = [];
$("#mrc_dst li").each(function() { dstA.push($(this).text()) });
$("#mrc_src li").each(function() { srcA.push($(this).text()) });
$.each(srcA, function (i,v) {
$('#mrc_imgimport span.fc').load('/wp-content/plugins/myplugin/imp.php?num='+i+'&dst='+dstA[i]+'&src='+srcA[i]);
});
});
});
This works pretty good but sometimes it looks like the load function isn't updating the DOM as fast as it should because sometimes the numbers that the span is updated with is lower than the previous and almost everytime a lower number is replacing the last number in the end. How can i prevent this from happening and how can i make it hide '#mrc_imp_img' when the $.each-loop is ready?
AJAX calls which have been called earlier are not guaranteed to finish earlier so the smaller number can overwrite the bigger. One solution is to simply increment the counter on each successful call:
jQuery(function($) {
$('#mrc_imp_img').click(function(){
var dstList = $("#mrc_dst li");
var srcList = $("#mrc_src li");
dstList.each(function(i) {
var dst = $(this).text();
var src = srcList[i].text();
$.post('/wp-content/plugins/myplugin/imp.php?num='+i+'&dst='+dst+'&src='+src, function() {
$('#mrc_imgimport span.fc').text($('#mrc_imgimport span.fc').text()+1);
});
});
});
});
(Changed the code to avoid unnecessary array operations, changed onready call to use shorthand, changed AJAX call to use POST which should be used for operations that change state.)
Most servers likely have a finite number of threads running. If you're firing off 10 calls at once, and your server only has 5 threads, 5 of them will fail.
Also - once you max out all the running threads, no other users can access the server, so you're essentially DOS-ing the server.
If you don't mind slowing it down to one call at a time, do what Tgr recommended which serializes the calls, waiting until each one completes before starting the next one.
I would prefer what Yoda suggested. What you can do is turn it into one server call that processes the entire array. If you really want to update a counter client-side, that one server call can update a counter in the database - and then a 2nd ajax call can poll the server every few seconds to find out where the counter is. Obviously wont be guaranteed to be sequential but will be better for your server health. You could also fake the sequential aspect (if you're on #3 and the next call yields a #6 - increment it client side one by one)
As far as not seeing an alert, there is probably a javascript error before or on the alert line. Try using firebug and the console.log statement, or even bette, step through it with the firebug debugger.