I have some slow OData calls which need to present some sort of visual indicator to the user that something is happening.
I've read the API reference and seen functions like attachRequestSent(), setBusy(), BusyDialog, BusyIndicator, etc.
I tried using them accordingly but did not work for me. The problem seems to be oModel.create causing the whole app to hang while it executes. No loading indicators or anything can run since the app is frozen until the create function has returned.
Edit: I have set up an asynchronous batch read OData call. I have then wrapped the code for handling the received data in a function and called that function inside the success function in the batch call.
This works; the view loads and I see a busy indicator before the fields are populated with the data
oModel.submitBatch(/*fnSuccess*/);
Is this a good way to do it, or is there a better way which is more standard?
Before the Odata call, display the busy indicator (locks the entire app screen). with
sap.ui.core.BusyIndicator.show(0);
Then, in both the success and failure handlers of the odata call, hide it with
sap.ui.core.BusyIndicator.hide();
It does not work with implicit calls (when for instance you bind to an odata model), for this you can use the request sent events, but the idea is the same.
Edit: You also need to give a small delay to allow the indicator to appear, then use setTimeout to call your odata after a small delay.
doStuffWithIndicator: function(){
sap.ui.core.BusyIndicator.show(0);
setTimeout(function(){
doStuff();
sap.ui.core.BusyIndicator.hide();
}, 20);
},
checkout this thread: SAPUI5 Wait for an Deferred-Object // wait for .done() function
Javascript is asynchrone, this means the code will be processed further no matter if you make an call (which might take longer). Therefore before calling an OData Service you need to tell your JS to wait for it (make it synchrone) via an deferred object.
The main problem seems to be oModel.create causing the whole app to hang while it executes. No loading indicators or anything can run since the app is frozen until the create function has returned.
Sounds like you've been using the now-deprecated sap.ui.model.odata.ODataModel the whole time, which sends mostly synchronous XHRs. Synchronous XHRs block the main thread (== UI thread) until the browser receives the response. The browser isn't then able to update the DOM to display the busy indicator during the round trip.
If anyone reading this has the same issue, please migrate to the newer equivalent model: sap/ui/model/odata/v2/ODataModel. It sends only asynchronous requests (AJAX), allowing the UI thread to handle other tasks (such as adding the busy indicator to the DOM) while the browser waits for the response.
Related
So i have a web application which is making around 14-15 AJAX calls to some APIs. The problem is the amount of time all the AJAX calls takes is nearly 3x than the time in which each individual API shows me response when I type its URL in the browser.
I am making all the AJAX calls instantly inside the DOM Ready event.
The thing is how can i speed up this process of making 15 AJAX calls together, getting the response as fast as possible and Manipulating the DOM accordingly.
Few Points which i have in my mind:
All the AJAX calls should be ASYNC in nature. (Already doing it).
Don't make all the AJAX calls at the same time. Induce some sort of timeout as making all the AJAX calls at the same time may block the bandwidth and slows down the turn around time of the process.
Reducing the number of API calls by any means. (Already doing it).
Manipulate the DOM as minimal as possible. (Already doing it).
Setting cache:true in AJAX setup. I don't think that will really help, still i am doing it wherever i am sure content will update really slow.
Any suggestions will be valuable! Thanks.
The way i am making AJAX calls
$(document).ready(function(){
loadSentimentModule();
loadCountModule();
loadEntitiesModule();
// Some more function calls.
});
function loadSentimentModule(){
$.ajax({
url:someurl,
cache:true,
dataType:"json",
success: function(data){
// Based on data manipulating DOM.
}
}
// Same kind of function defintions for all the functions.
You may not issue the ajax call directly, but queue them and let a manager control the queue, see here: Queue ajax requests using jQuery.queue()
I recomend you to use the async.js module on client. May be it this what are you looking for.
I have a site I'd like to check through several environments for login credentials, but in the mean time, display a loading gif.
Trouble is, if I make the ajax synchronous or,
async: false,
then the rest of the page pauses until the credentials are checked.
I tried switching the ajax calls back to asynchronous, it will prematurely display a false negative error that the user isn't logged in, since it hasn't finished checking all environments.
I also tried a kind of band-aid solution with
setTimeout(loginCheckFunction, 600)
But that's arbitrary timing, and if the user has a slow connection, the false error will persist.
Any ideas on how to make some portions run without waiting for the synchronous Ajax to finish?
Thanks!
edit:
I think my issue is pretty much inadvertently solved by this question:
How to display 'Loading' when making a 'synchronous' AJAX call in pure JavaScript?
edit 2:
I skirted the issue by using the top answer to the above question. I gave a very small setTimeout function to the beginning of parent function calling the synchronous ajax-based login checks, during which time the 'loading' gif can be launched, and viewed simultaneously while ajax runs.
Per the answer given though, in the strictest sense, it isn't running simultaneously, the browser just provides that illusion.
For future persons maybe running into similar issue, I transitioned from setTimeout being applied on the child function, to setTimeout being applied one level up on its the parent function.
Have you tried do one ajax call after another ajax call ends?
First you show your loading screen and do the ajax calls one after another ends. In the last call you hide your loading. In this way you parallelize all the ajax call, validating each pass.
You can use the Ajax Queue plugin
A web application has certain timeliness constraints. How can I check the time from invocation of a JS function to having the information visible in the browser?
Clearly I can start a stopwatch, but on what event should I stop it?
Modern browsers offer the Navigation Timing API, which you can use to get this kind of information. Which information from it you use is up to you, probably domComplete or loadEventStart (or, of course, loadEventEnd if you want to know when everything is fully loaded, but you could do that with window.onload). This tutorial may be useful.
If you're talking about requesting something via ajax after page load (you've said "...from invocation of a JS function to having the informatin visible in the browser..."), adding that to the page, and seeing how long that took, you'd stop the timer after you were done appending the elements to the DOM, immediately before returning from your ajax onreadystatechange handler callback. Or if you want to be really sure the information has been rendered, after using setTimeout(function() { /*...end the timer...*/ }, 0); from that callback instead, which yields back to the browser for the minimum possible time, giving it a chance to render (if it doesn't render while JS is running).
Does JSVM run just in one thread?
I am wondering how the JavaScript function executing inside the VM.
The source code below is interesting:
// include jQuery as $
function test() {
$.ajax({url:"xxx.com"})
.success(function() {alert("success 1");})
.fail(function() {alert("fail 1");});
$.ajax({url:"yyy.com"})
.success(function() {alert("success 2");})
.fail(function() {alert("fail 2");});
while(true);
}
It will make die loop at the "while" line and never pop up any alert dialog to show neither "success" nor "fail".
We know inside the $.ajax, the VM creates XMLHttpRequest and sends a HTTP request.
After sending out two requests, it meets the "while" line.
Thus I image that the JSVM:
1) can handle only function call at one time. (function is atomic)
2) follow the rule: first comes, first served.
Does my idea right?
Does anyone can explain the internal implementation of JSVM?
More specific,
If using AngularJS to develop a front end app, we would like to do something and then immediately record a log to remote server in form submit event like ng-submit.
function ngSubmitTest() {
doA();
recordA(ajax, remoteServer); // must after doA()
}
If recordA uses AJAX, we should ensure recordA is complete before ng-submit redirect the page meanwhile kill the old page and also the VM (if the old page is killed, the recordA may not complete). One solution is doing AJAX with async=false. And I wonder if there is any other solutions?
Thanks.
The implementation of JS depends on the context you're runing it.
Each browser has it's own implementantion, and they can do whatever they want as long as they follow the language specification.
It shouldn't bother you if it runs on one or multiple threads, but you can be sure JavaScript is not a "threaded" language, it works with an event loop flow, in which an event is fired, and consecutive functions are fired after that, until there is nothing more to call. This is the reason why it's pretty hard to block the UI in JavaScript if you're writing "good" code.
A good example on how this works, and the diferences betwen event loops and classic threading, is node.js, i'll give you a example:
Supose you're listening for a request on a server, and 2 seconds after the request arrives you'll send a message. Now let's supose you duplicate that listener, and both listeners do the same thing. If you request the server, you'll get the two messages at the same time, 2 seconds after the request is made, instead of one message on 2 seconds, and the other one on 4 seconds. That means both listeners are runing at the same time, instead of following a linear execution as most systems do.
Node runs Chrome's V8 if you're wondering, it's a very professional JS interpreter and it was a breakthorugh when it came out.
I have a web application that is growing more complex. It makes heavy use of JavaScript based HTML generation and AJAX calls, and herein lies my problem:
Since I can't know how long an ajax call might take getting back to client side, I don't know when the callback gets actually executed. The user might have at that point navigated away from the element that originally caused the AJAX event, in which case this callback can cause some havoc. Is there a way to "expire" old callbacks ?
Are there any libraries that would offer that functionality? (I am using jQuery now but am not 100% familiar with it).
Thanks,
You might want to look into Ajax Queue Manager. There are params you can set to abort old requests before sending a new one. I think that might be what your looking for.
Well, the simple answer is to check for the proper state of your app within your callback functions, before they do whatever it is they are doing that causes problems. For example, you could make sure that certain elements are still being hovered over.