Javascript Blocking Call - javascript

How do I do a blocking call in javascript?
In the code below the alert at the last line of this code snippet hits before the code in if block completes which returns some value, by calling chached.get method in different js file.
var getCachedData = function(_key){
var retStr;
if (_key != '' || _key != null) {
cached.get(_key, function(data){
if(data){
alert('data = ' +data.value);
return data.value;
}
else{
return undefine;
}
});
}
alert('completed');
}

The cached.get method must be doing something asynchronously. The function you supply to that method as an argument appears to be a callback function that executes once the get method has returned successfully. If you need to run code that is dependant on the result of the call to cached.get, you will need to put it inside that callback.

It will depend on the library (i.e. whatever defines the behaviour of cached in your case) whether you can block or not. You'll have to provide more information about what cached is, or figure it out yourself.
However, generally speaking you want to avoid blocking in Javascript as much as possible, since Javascript runs in the UI thread for every major browser (as far as I know).
Instead of expecting to be able to block, rewrite your code so that you use data inside your callback function.

Related

Check for pending AJAX call and wait until it finishes

Is there a way, raw JavaScript or via a plugin, that will detect if a given function has an AJAX call inside? I've been working with API's recently, and it often occurs to me that some of my codes ran "a little bit earlier" than it supposed to because the previous script contains an async AJAX call. For instance:
var doSomething = function(by, activity) {
// Call something from the API of from another developer
// or a function() from a 3rd party JS library.
var anonFunction = API.package[by][activity]; // or anonFunction = 3rpPartyJS();
if(anonFunction === undefined) {
return "skipped";
}
else {
var response = anonFunction();
// The problem is that the code below will execute not knowing whether
// there are still AJAX call/s pending within the var anonFunction
// initialization. If there is indeed an AJAX call (which sometimes there
// aren't, depends on the <function name> called above), the script below
// will be executed a little bit earlier than it should be.
if(response["success"] === true) {
... // do something
return "done";
}
else {
alert("Failed to call function " + by + "." + me);
return "fail";
}
}
}
$(function() {
// This is successful.
doSomething("me", "aSyncFunction");
// This returns "fail", even thought the response returns
// successful (after some X milliseconds later).
doSomething("me", "anAsyncFunction");
});
I know how to do AJAX promises on JQuery, although it could take me forever to re-code the AJAX call inside those external JS files. Plus configuring those external JS files would be dangerous, I don't even know if there are other pages that use those JS, that may be affected. Dropping the "re-coding" as solution, I'm looking for an alternative function to check if:
There is/are AJAX call inside a function (, and subsequently, every other subfunction/s that is/are been called inside that function).
And if there is, would make the browser "wait" until the AJAX calls finish, before running the next line.
Currently, I'm using a clumsy solution that utilizes something similar to sleep() function, but I know that is not a good solution. I need something like:
}
else {
var response = anonFunction();
while($.activeAJAX().length !== 0) // <<< something like this
// will do nothing and wait.
}

How to run javascript function in web browser only when is not proccesing that function

One of my javascript function is processing millions of data and it is called ~1 time every second from a hardware event. Then the web browser is idle in that function processing.
I tried to set a flag for running (or not running) that function:
if (!is_calculating)
is_calculating = true;
else
return;
my_function(); // do heavy stuff
is_calculating = false;
but it's not working, because it is entering into the code and the web browser enter in an idle status until is finishing. When it is returning, the flag is always OK, because it finished the // do heavy stuff
Can I do something for this behavior? I'd like to jump function execution if a flag is set.
The problem is, by default javascript runs in a single thread on browsers, so your code is executing completely before it even begins to process the next call, resulting in is_calculating always being false when the function is called. One workaround you could use (not the cleanest solution in the world), is to divide your monolithic 'heavy stuff' function into a number of smaller functions and have them call each other with setTimeout(nextFunc, 1). Having them call each other that way gives the browser a moment to do what it needs to do, and additionally call your function again if that's what it's doing. This time, because your function is called in the 'middle' of it already being executed, is_calculating is still going to be true, and the call will return at the beginning like you expect it to. Note this solution probably isn't as preferable as the Web Workers solution, but it is simpler.
function sleep(millis) {
var date = new Date()
var curDate = null
do { curDate = new Date() }
while(curDate-date < millis)
}
function reallyLong() {
if(!reallyLong.flag) {
reallyLong.flag = true
} else {
console.log("Not executing")
return
}
sleep(250)
setTimeout(reallyLong2, 1)
function reallyLong2() {
sleep(250)
setTimeout(reallyLong3, 1)
}
function reallyLong3() {
sleep(250)
setTimeout(reallyLong4, 1)
}
function reallyLong4() {
sleep(250)
console.log("executed")
reallyLong.flag = false
}
}
If you define all your consecutive functions inside the primary function, it also allows them all to access the same data simply and easily.
The only catch now is if your function was returning some value, you need to rewrite it to either return a promise (Either of your own design or using a library like Q), or accept a callback as a parameter that the last function in the 'chain' will call with the return value as a parameter.
Note that the sleep function above is a hack, and awful, and terrible, and should never be used.
By default JavaScript execution in browsers is not concurrent. This means, usually there can be only one currently executing piece of code.
You have to use Web Workers API to make you code run concurrently.

Function inside chrome extension script is returning the wrong value

I'm writing a function for a chrome extension that gets the status ('loading' or 'complete') of the current tab.
currentTabId is a global variable.
function getTabStatus() {
var tabStatus = "foobar";
chrome.tabs.get(currentTabId, function(tab) {
tabStatus = tab.status;
});
return tabStatus;
}
I would expect this function to return 'loading' or 'complete' but it's returning 'foobar'.
If I set a breakpoint in Chrome developer tools on the 5th line (tabStatus = tab.status), the function has already returned 'foobar' but still stops at the breakpoint.
This is due to asynchronous programming. chrome.tabs.get executes, but return tabStatus runs before tabStatus = tab.status. You need to arrange your code in such a way that it continues running from within the chrome.tabs.get.
What's going on is, chrome.tabs.get is passed a callback (your anonymous function function(tab)) to execute when it is done doing the get, so the code is tabStatus = tab.status is actually running after your code does the return tabStatus.
You need to rewrite your code sort of like this:
function getTabStatus() {
var tabStatus = "foobar";
chrome.tabs.get(currentTabId, function(tab) {
tabStatus = tab.status;
doSomething(tabStatus);
});
}
Rather than doing a call-return style, you need to call another method that will continue the execution of your code.
The reason why this is done is so your code doesn't have to wait for get to execute before it continues running, sort of like multithreading. It allows your code to branch into two directions that can perform two different code paths at the same time, but some variables won't be in the correct scope, so that's when you encounter issues like this.
You can read more about asynchronous programming here.

Javascript Asynchronous Return Value

Just as I thought I understood JS scope...
Take this code:
function init() {
var page;
var pageName = $('body').data('page');
switch(pageName) {
// (there are more switch cases here normally...)
case 'pSearchLatest':
require(['searchresults'], function (SearchResults) {
page = new SearchResults().init();
console.log(page); // <- shows the object!
});
default:
break;
}
console.log(page); // <- undefined
return page;
}
See the console log comments. Why is the second returning undefined when the var page is declared outside of the scope of the switch statement?
EDIT
So I mistakenly thought this was a scope issue but it's down to the asynchronous nature of AMD.
How can I return the value of page in the require scope in the same method without a while loop checking for undefined?
EDIT 2
I did it like this:
function init(callback) {
case 'pSearchLatest':
require(['searchresults'], function (SearchResults) {
page = new SearchResults().init();
callback(page)
});
}
and in my page that calls the wrapping init() method:
new PageController().init(function(asyncViewController) {
App.view = asyncViewController;
});
You did understand scope correctly. The code in that inner function does indeed assign to the variable in the outer scope.
What you did not understand is asynchronous behaviour. The require function takes a callback function which will be invoked somewhen in the future - when the requested module is available. Yet, it does immediately return and control flow will lead to the console.log statement, which does print undefined - which is the value the page variable has at that time.
You should be able to recognise that since the undefined is logged first, and the log statement in the callback (with the object) executes later, even though it comes above in the code.
require is asynchronous, therefore your function did exit first and then processed callback function.
Two possible reasons... you didnt match the case. or the callback where the assignment of the value to page happens hasnt been executed yet. Im guessing its the latter since it would be readily apparent if you case was failing. Look into the documentation for whatever AMD library youre using and see how the execution of the function(s) passed to require are executed.
Also as a generaly rule try to avoid returning values determined by asynchronous calls like this. Instead use some kind of Observer pattern to subscribe to a particular event that can be triggered from different places.

JQuery / Javascript inline callback

In tornado we have gen module, that allows us to write constructions like this:
def my_async_function(callback):
return callback(1)
#gen.engine
def get(self):
result = yield gen.Task(my_async_function) #Calls async function and puts result into result variable
self.write(result) #Outputs result
Do we have same syntax sugar in jquery or other javascript libraries?
I want something like this:
function get_remote_variable(name) {
val = $.sweetget('/remote/url/', {}); //sweetget automatically gets callback which passes data to val
return val
}
You describe the function as "my_async_function", but the way you use it is synchronous rather than asynchronous.
Your sample code requires blocking -- if "my_async_function" were truly asynchronous (non-blocking), the following line of code self.write(result) would execute immediately after you called "my_async_function". If the function takes any time at all (and I mean any) to come back with a value, what would self.write(result) end up writing? That is, if self.write(result) is executed before result ever has a value, you don't get expected results. Thus, "my_async_function" must block, it must wait for the return value before going forward, thus it is not asynchronous.
On to your question specifically, $.sweetget('/remote/url/', {}): In order to accomplish that, you would have to be able to block until the ajax request (which is inherently asynchronous -- it puts the first A in AJAX) comes back with something.
You can hack a synchronous call by delaying the return of sweetget until the XHR state has changed, but you'd be using a while loop (or something similar) and risk blocking the browser UI thread or setting off one of those "this script is taking too long" warnings. Javascript does not offer threading control. You cannot specify that your current thread is waiting, so go ahead and do something else for a minute. You could contend with that, too, by manually testing for a timeout threshold.
By now one should be starting to wonder: why not just use a callback? No matter how you slice it, Javascript is single-threaded. No sleep, no thread.sleep. That means that any synchronous code will block the UI.
Here, I've mocked up what sweetget would, roughly, look like. As you can see, your browser thread will lock up as soon as execution enters that tight while loop. Indeed, on my computer the ajax request won't even fire until the browser displays the unresponsive script dialog.
// warning: this code WILL lock your browser!
var sweetget = function (url, time_out) {
var completed = false;
var result = null;
var run_time = false;
if (time_out)
run_time = new Date().getTime();
$.ajax({
url: url,
success: function(data) {
result = data;
completed = true;
},
error: function () {
completed = true;
}
}); // <---- that AJAX request was non-blocking
while (!completed) { // <------ but this while loop will block
if (time_out) {
if (time_out>= run_time)
break;
run_time = new Date().getTime();
}
}
return result;
};
var t = sweetget('/echo/json/');
console.log('here is t: ', t);
Try it: http://jsfiddle.net/AjRy6/
Versions of jQuery prior to 1.8 support sync ajax calls via the async: false setting. Its a hack with limitations (no cross-domain or jsonp, locks up the browser), and I would avoid it if possible.
There are several available libraries that provide some syntactic sugar for async operations in Javascript. For example:
https://github.com/caolan/async
https://github.com/coolaj86/futures
...however I don't think anything provides the synchronous syntax you are looking for - there is always a callback involved, because of the way JavaScript works in the browser.

Categories

Resources