2

I know this question has been asked many times in many different ways, but I am still having trouble identifying a good solution to the following problem.

How can I wait for the callback of this asynchronously-executed inner function to complete prior to returning from the outer function?

function outer() {
    var result = false;
    var innerAsynch = function() {
        result = true;
    }
    setTimeout(innerAsynch, 1000);
    waitForInnerAsynch(); //blocking
    return result;  //true
}

1) I am well aware that this is bad practice for 99.999% of use cases, so please don't tell me that it shouldn't be done!

2) Please feel free to completely restructure this code... my only requirement is that outer() returns something which blocks the browser until innerAsynch() is done and passes the following test:

 if(outer()) {
    //1 second later.... yippee!
 }

Also I am using jQuery, but I would prefer not to use a plugin unless it really makes sense to do so. Thanks!

Update

I want to reiterate that my goal is to fully encapsulate the asynchronous execution within the synchronous call to outer() without arguments.

In other words, this should work:

<a href="something" onclick="return outer()">A very slow link</a>

Perhaps this is not actually possible, in which case I am fine using callbacks, but I want to develop a better understanding of why that is the case.

3
  • 1
    Blocking is not the way to do it in js. Take a look into promises - api.jquery.com/category/deferred-object Commented Nov 12, 2012 at 18:13
  • @bfavaretto - Good suggestion. Before posting I was looking into promise objects but I am having adapting that concept to this example. Commented Nov 12, 2012 at 18:23
  • deferred jquery objects are based on callbacks. jQuery just abstracts them Commented Nov 12, 2012 at 18:27

2 Answers 2

1

Standard js pattern. You just need to use callbacks:

function outer(callback) 
{
    var innerAsynch = function(innerCallback) {
        var result = true;
        innerCallback(result);
    }

    setTimeout(function()
    {
      innerAsynch(function(result)
      {
        callback(result);
      });

    }, 1000);
}

Usage:

outer(function(result)
{
  if ( result )
    //true
  else
    //false
});
Sign up to request clarification or add additional context in comments.

8 Comments

Looks to me like outer will return immediately after calling setTimeout. How does this answer the question?
It's really confusing that you use the same variable name result in 3 different places, but these are actually different variables (aren't they?).
The variable result in the function outer was not needed
I still don't see how this waits for the timeout. outer still returns immediately, it's just that the callback function doesn't get called until later. And outer doesn't return a value, so it can't be used in an if.
@KirillIvlev - this works and I have tested in JS Fiddle, but I would like to avoid the callback if possible. Is there not a way for the outer() call to take 1 sec and return true without a callback argument?
|
1

I want to reiterate that my goal is to fully encapsulate the asynchronous execution within the synchronous call to outer() without arguments.

Asynchronous execution and callbacks exist for the sole reason of not blocking. If you really want to block, don't use async code. If you do depend on async functions, re-structure your code to use callbacks. It's simple as that.

JavaScript is single-threaded, so, if you block, the browser will seem to freeze until your code unblocks. When you block, you can't even update the UI to notify the user that some long-running operation is being performed. That's why it's bad. Keep in mind that the language was designed around an event loop and a queue of asynchronous events; trying to go against that will just lead to a big headache.

2 Comments

I fully understand what you are saying, and I know that this is not a normal request in browser land. I have a very specific use case where I am creating an adapter for iOS confirmation notifications created by Phonegap so that they act like a call to window.confirm() which is a blocking operation. They use a callback mechanism which I would like to wrap in a synchronous method call, hence the reason I am asking this question.
If you really want it to behave like window.confirm(), I guess your only option is writing it in native Objective C code, and then add a js interface to it. Native code should be able to block the whole UIWebView thread (but I know very little about Phonegap and Obj C, so correct me if I'm saying something stupid). In JS/HTML you must use an overlay div to block the UI, and create a modal-like dialog on top of that. JavaScript does not provide any way to block as you wish to do, hence the headache I mentioned...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.