javascript calling DataSnap REST makes browser unresponsive - javascript

I use Delphi XE7. When my Javascript calls my server function that need around 800ms to read sensor and return data, The browser is unresponsive from the moment I click the button to invoke the Javascript until it finally response returns. I'm using the default Javascript generated by the proxy var serverMethods().getChannel(i); to call into my server function.
Javascript call look like this:
var s = serverMethods().getChannel(i);
serial[i].$sensorlValue.text(s.result.fields.sensorString);
serial[i].$sensorlRealValue.text(s.result.fields.sensor);
serial[i].$sensorStatus.text(s.result.fields.sensorStatus+' '+s.result.fields.name);
serial[i].$sensorError.text(s.result.fields.sensorError);
serial[i].$AVString.text(s.result.fields.AVString);
serial[i].$AVError.text(s.result.fields.AVError);
So by default example there are no Javascript callbacks or promise, so embaracaderom manage somehow to block Javascript from executing until response is back and variable a receive values?
I think about try using jQuery Ajax call on URL, but is there any other solution?
Because serverMethods are generated from proxy but for $ajax I need to manually set each of them. Or maybe I do something wrong here and serverMethods can be used without blocking ?
Thanks.

I found the solution to this problem after researching execution path in ServerFunctionExecutor.js that is called on serverMethods().SOMEAPIFUNCTION()
1. Help and documentation are 0, and google + XE7 questions are 0. So if someone from embaracadero read this PLS MAKE DECENT DOCUMENTATION.
ServerFunctionExecutor.js had on line 263
//async is only true if there is a callback that can be notified on completion
var useCallback = (callback != null);
request.open(requestType, url, useCallback);
if (useCallback)
{
request.onreadystatechange = function() {
if (request.readyState == 4)
{
//the callback will be notified the execution finished even if there is no expected result
JSONResult = hasResult ? parseHTTPResponse(request) : null;
callback(JSONResult, request.status, owner);
}
};
}
So it is posible and NOT DOCUMENTED to use callback for unblocking GUI.
Use it as:
serverMethods().SOMEAPIFUNCTION(par1,par2,.... callback)
If you have Server method defined in delphi code with for example 3 parameters in js 4th parameter is callback:
For this example code now look like this:
serverMethods().getChannel(i,function(a,b,c){
serial.$sensorlValue.text(a.result[0].fields.sensorString);
serial.$sensorlRealValue.text(a.result[0].fields.sensor);
serial.$sensorStatus.text(a.result[0].fields.sensorStatus+' '+s.result.fields.name);
serial[i].$sensorError.text(a.result[0].fields.sensorError);
serial[i].$AVString.text(a.result[0].fields.AVString);
serial[i].$AVError.text(a.result[0].fields.AVError);
});
a is JSON reponse
b is Request status as number 200 or somethin else
c is owner usuali undefined

Related

Can an existing synchronous function call be replaced with one relying on async/await?

I am trying to replace an existing function call with one that calls out to parent frame PostMessage and receives another related PostMessage message back with a value.
I am trying to have as little disruption to existing code as possible since there are a couple hundred lines where it is called.
Current code is like the following...
function thisfunc(){
return checksomethingincurrentpage()
}
if(thisfunc() == 'something')
// do something
// do something else
When switched to be based on PostMessage send/receive from parent fraome, can thisfunc() one way or another not return until the corresponding PostMessage is received and do so in the same execution path?
I was trying something like this but does not look like it works. (I don't have the test code anymore)
//pseudocode...
resolvefunc = null;
function getprom()
prom = new promise
set resolvingfunc equal to resolve function
postmessagecall;
return prom;
async function thisfunc()
response = await getprom();
return response;
eventListener for post message
receive post message
resolvefunc(postmessagepayload)
if(thisfunc() == 'something')
// something
I saw that XMLHttpRequest could be made to be synchronous but doesn't help in this case with PostMessage.
Is this possible? How?

One entry point for all ajax callbacks for a particular call in javascript

When communicating with a server in javascript in my single page browser application, I would like to provide a callback function that is always called after the server replies, regardless of whether the result was a success or some kind of error.
Two cases where I need this:
1) I want to disable a "save" button while waiting for the server's response, and enable it again after the server responds with an error or a success.
2) I have a polling mechanism where I want to prevent stacking of calls when the server for some reason is being slow to respond - I want to wait for one poll call to finish before making the next.
One solution I have right now involves making sure that two functions (success and error) get passed along as options in a long method chain, which feels like a fragile and cumbersome solution (pseudo-ish code):
function doCall() {
framework1.callit({success : myCallback, error : myCallback})
};
framework123.callit = function(options) {
options = options || {};
if (options.error) {
var oldError = options.error;
options.error = function(errorStuff) {
// callit error stuff
oldError(errorStuff);
} else {
// callit error stuff
}
generalCallFunction(options);
}
function generalCallFunction(options) {
options = // ... checking success and error once again to get general success and error stuff in there, plus adding more options
ajax( blah, blah, options);
}
I also have a backbone solution where I listen to the sync event plus an error callback, in similar ways as above.
I'm always scared that error or success functions get lost on the way, and the whole thing is hard to follow.
Any framework or pattern for making this stuff as easy as possible? Is it a weird thing to have general things that should always happen whether the result was an error or a success?
You can use jQuery.ajax({ details here... ).always(callback);
Or, in Backbone
// logic to create model here
model.fetch().always(callback);

issue with JSONP getting a cached response from a WCF service

I use JSONP on a client to get data from a server using a WCF service that can return results using HTTP GET (It gets a 'callback' parameter which is a 'function name' and returns callback({data}), you know... JSONP).
Everything works, but if I enable caching (using 'AspNetCacheProfile')on one of the service's operations - then something is wrong, and I'm not sure what...
The way I get the JSONP is by using a function I picked up some time ago from a question here on SO (http://stackoverflow.com/questions/2499567/how-to-make-a-json-call-to-a-url)
function getJSONP(url, success) {
var ud = 'fc_' + + Math.floor(Math.random()*1000000),
script = document.createElement('script'),
head = document.getElementsByTagName('head')[0]
|| document.documentElement;
window[ud] = function(data) {
head.removeChild(script);
success && success(data);
};
script.src = url.replace('callback=?', 'callback=' + ud);
head.appendChild(script);
}
This creates a random id ('fc_xxxx') then assigns it as a function inside the window object, then use it as the 'callback' parameter for the url of the dynamic javascript that is injected to the document, and then the 'ud' function runs, removes the script and calls the 'success' callback function with the received data.
When using it on normal uncached operations from the service, it usually takes about 200ms to get back the response, and it works ok. The cached responses takes ~10ms -
and I get an error that the 'fc_XXXXX' function is undefined.
It's as if the response is "too fast" for it.
I also tried using jQuery.getJSON() - and, again the callback doesn't trigger.
In all cases when I look at the network traffic in Firebug - I can see the GET request, and I can see that the right data does in fact gets returned.
Does anybody have an idea how can I make it work right with the cached responses...?
I got it! The name of the response-function is different on each call (on both my manual jsonp implementation and that of jQuery).
The name of the function is part of the response from the server (as that's part of how jsonp works...).
So, if the response is a cached response - it will actually return the old name of the function (which will no longer exist on the client's context).
So I just need to give a constant name for the callback function in this case and it should bee fine. :)

what is the right way to manage multiple ajax requests?

We've all seen some examples in AJAX tutorials where some data is sent. They all (more or less) look like:
var http = createRequestObject(); // shared between printResult() and doAjax()
function createRequestObject() { /* if FF/Safari/Chrome/IE ... */ ... }
function printResult()
{
if (http.readyState == 4) { ... }
}
function doAjax() {
var request = 'SomeURL';
http.open('post', request);
http.onreadystatechange = printResult;
data = ...; // fill in the data
http.send(data);
}
// trigger doAjax() from HTML code, by pressing some button
Here is the scenario I don't understand completely: what if the button is being pressed several times very fast? Should doAjax() somehow re-initialize the http object? And if if the object is re-initialized, what happens with the requests that are being already on air?
PS: to moderator: this question is probably more community-wiki related. As stated here (https://meta.stackexchange.com/questions/67581/community-wiki-checkbox-missing-in-action) - if I've got it right - please mark this question appropriately.
Since AJAX has asynchronus nature, with each button click you would raise async event that would GET/POST some data FROM/TO server. You provide one callback, so it would be triggered as many times as server finishes processing data.
It is normal behaviour by default, you should not reinitialize of http object. If you want to present multiple send operation you have to do that manually (e.g. disabling button as first call being made).
I also suggest to use jQuery $.ajax because it incapsulate many of these details.
Sure that numerous libraries exist nowadays that perform a decent job and should be used in production environment. However, my question was about the under-the-hood details. So here I've found the lamda-calculus-like way to have dedicated request objects per request. Those object will obviously be passed to the callback function which is called when response arrives etc:
function printResult(http) {
if (http.readyState == 4) { ... }
...
}
function doAjax() {
var http = createRequestObject();
var request = 'SomeURL';
http.open('get', request);
http.onreadystatechange = function() { printResult(http); };
http.send(null);
return false;
}
Successfully tested under Chrome and IE9.
I've used a per-page request queue to deal with this scenario (to suppress duplicate requests and to ensure the sequential order of requests), but there may be a more standardized solution.
Since this is not provided by default, you would need to implement it in JavaScript within your page (or a linked script). Instead of starting an Ajax request, clicking a button would add a request to a queue. If the queue is empty, execute the Ajax request, with a callback that removes the queued entry and executes the next (if any).
See also: How to implement an ajax request queue using jQuery

How to obtain jquery post return values?

I want to retrieve the height and width of an image on a server by using an ajax post call to a php file which returns a double pipe delimited string 'width||height'
My javascript is correctly alerting that requested string from the php file so the info is now in my script but i cannot seem to access it outside the $.post function.
This works:
var getImagesize = function(sFilename)
{
$.post("getImagesize.php", { filename: sFilename, time: "2pm" },
function(data){
alert(data.split('||'));
});
}
But retrieving is a different matter:
// this line calls the function in a loop through images:
var aOrgdimensions = getImagesize($(this, x).attr('src')) ;
alert(aOrgdimension);
// the called function now looks like this:
var getImagesize = function(sFilename)
{
var aImagedims = new Array();
$.post("getImagesize.php", { filename: sFilename },
function(data){
aImagedims = data.split('||');
});
return "here it is" + aImagedims ;
}
Anyone able to tell me what i'm doing wrong?
You are misunderstanding the way that an AJAX call works. The first "A" in AJAX stands for asynchronous, which means that a request is made independent of the code thread you are running. That is the reason that callbacks are so big when it comes to AJAX, as you don't know when something is done until it is done. Your code, in the meantime, happily continues on.
In your code, you are trying to assign a variable, aOrgdimensions a value that you will not know until the request is done. There are two solutions to this:
Modify your logic to reconcile the concept of callbacks and perform your actions once the request is done with.
Less preferably, make your request synchronous. This means the code and page will "hang" at the point of the request and only proceed once it is over. This is done by adding async: false to the jQuery options.
Thanx for the Asynchronous explaination. I did not realize that, but at least now i know why my vars aren't available.
Edit: Figured it out. Used the callback function as suggested, and all is well. :D

Categories

Resources