Detemining time to screen for a web app - javascript

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).

Related

A quest to prevent `window.location.reload()` before `load`

So this is more of a curiosity, rather than a problem I'm facing. I've come across a website that calls window.location.reload() before the load event fires. How would you break out of this refresh loop, as a user? Can it even be done?
Anyways, I've tried the following:
Replacing window.location.reload (via greasemonkey)
This is not possible since window.location is read-only.
Listening for window.onbeforeunload and hitting cancel (via greasemonkey)
The reload call happens before the document loads. This means the beforeunload event is never fired due to lack of transient activation, so there's no prompting for you to cancel the reload.
Block JavaScript (or: block all network requests)
This does disable the reload. And also the entire site, so it's not ideal.
Block the request to the specific file with the reload call (via devtools)
Same as above, since the file in question is a Webpack bundle, containing the majority of the site's functionality.
Inject a userscript that replaces the function calling windows.location.reload() with an equivalent function that doesn't call windows.location.reload() (via greasemonkey)
I don't think it's possible for this site. Webpack loads every function in an IIFE, so it's not obvious how to modify the function in question before it gets passed as a callback and becomes untouchable. In any case, this approach doesn't generalize.
Place a breakpoint at the window.location.reload call, and modify some local function to throw an error before it can call reload (via devtools)
This didn't work (on Firefox, at least) -- try it out, (function() {throw new Error(), window.location.reload()})(). Due to the comma operator, it'll reload despite the thrown error, and every Webpack expression seems to be a string of comma-separated statements so there's no avoiding this. This approach also doesn't generalize.
Manually modify the construction of the global Webpack window.webpackChunk_N_E table (via greasemonkey)
I don't know about modern Webpack to know if this could be done, but I tried replacing the particular method in question in that table with a ()=>{}. It didn't work -- I believe the method was already passed as a callback before the tire change. We are dealing with a function that is far too powerful to care about its replaced reference in some mere global table.
Close the tab
I gave up.
Did I miss anything obvious, or is it impossible by design to break this particular kind of refresh loop in the browser (short of disabling JavaScript)?

Why are busy indicators not displayed when sending requests?

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.

Force Synchronous function execution with callbacks

I have one opportunity to manipulate the DOM of my page before it's styled, rendered and shown to the user.
Obviously, I'd love to do all the dynamic fun stuff within this window as DOM manipulations are very expensive after the page as rendered. Since this is primarily targeted at mobile devices, this optimization is valuable to me.
Here's a basic overview / timeline:
function CalledBeforePageRendered(){
DoAsyncDataBaseWorkWithCallBack(AsyncDataBaseCallBack);
DoLocalizationsAndOtherSYNCRONOUSActions();
}
function AsyncDataBaseCallBack(results){
// code that processes the results element
// code that manipulates the DOM *before* it's styled.
}
The problem is that DoAsyncDataBaseWorkWithCallBack and DoLocalizationsAndOtherSYNCRONOUSActions
finish quickly and then CalledBeforePageRendered returns and subsequent styling is applied.
After the styling is applied, the page is shown to the user... and then AsyncDataBaseCallBack gets called
which then applies div tags and other DOM modifications. Only, I needed these modifications to take place before stylization
Is there any way I can make 'CalledBeforePageRendered' wait for 'AsyncDataBaseCallBack' to finish before returning? I know that a closure would usually work here, but I do not know how to make a closure work with a callback that is defined outside of the CalledBeforePageRendered function.
If you are trying to perform a synchronous JavaScript XmlHttpRequest (XHR) call - that's very possible, but assuming your trying to manipulate the DOM on the client side before the page is rendered - why don't you do that on the server side (since it's generating the HTML in the first place). If you can't I highly recommend you don't perform a synchronous JavaScript XHR to update the page before it's rendered. Doing so will lock up the browser window while the XHR is running which can not only add significant latency to page loading - it also frustrates end users (since they experience what appears to be a hard 'lock'). Manipulating the DOM before it's rendered isn't that costly. It's better to return the HTML you want in the first place though - instead of loading more after the page has loaded.
Again - I'd just like to emphasize - try to do this work on the server side (not client). If you can't and need to perform this as a secondary call - add a loading image and let XHR's run asynchronously like most JavaScript libraries pretty much enforce anyways. If I am misunderstanding your goals, please let me know.

How can I track AJAX calls and determine whether calling the callback function is no longer necessary?

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.

How can I have a JS script update a page for everyone viewing it?

I'm creating a web application that allows users to make changes through Javascript. There is not yet any AJAX involved, so those changes to the DOM are being made purely in the user's local browser.
But how can I make those DOM changes occur in the browser of anyone else who is viewing that page at the time? I assume AJAX would be involved here. Perhaps the page could just send the entire, JS-modified source code back to the server and then the other people viewing would receive very frequent AJAX updates?
Screen sharing would obviously be an easy work-around, but I'm interested to know if there's a better way, such as described above.
Thanks!
You are talking about comet, for an easy implementation i'd suggest:
http://www.ape-project.org/
and also check these:
http://meteorserver.org/
http://activemq.apache.org/ajax.html
http://cometdaily.com/maturity.html
and new html5 way of it
http://dev.w3.org/html5/websockets/
Hope these help.
Max,
Ajax will have to be involved. If i may, I'd like to suggest jQuery as a starting point for this (i know you didn't tag as such, but i feel it'd be appropriate, even if only to prototype with). the basic semantics would involve running the ajax request in combination with a setInterval() timer to fire off the ajax request. this could be done in jQuery along the lines of:
$(document).ready(function() {
// run the initial request
GetFreshInfo();
// set the query to run every 15 seconds
setInterval(GetFreshInfo, 1500);
});
function GetFreshInfo(){
// do the ajax get call here (could be a .net or php page etc)
$.get('mypageinfostuff.php', null, function(data){$('#myDivToUpdate').html(data);});
}
that's the basic premise... i.e the webpage is loaded via GetFreshInfo() initially straight away, then it's requeried every 15 seconds. you can add logoc to only refresh the div if there is new data there, rather than always updating the page. as it's ajax, the page won't freeze and the process will be almost invisible to the user (unless you want to flag the changes in any way)
Hope this helps
jim

Categories