How to call an asynchronous JavaScript function and block the original caller

前端 未结 5 984
耶瑟儿~
耶瑟儿~ 2020-12-28 16:57

I have an interesting situation that my usually clever mind hasn\'t been able to come up with a solution for :) Here\'s the situation...

I have a class that has a g

相关标签:
5条回答
  • 2020-12-28 17:16

    spawn a webworker thread to do the async operation for you. pass it info it needs to do the task plus a unique id. the trick is to have it send the result to a webserver when it finishes.

    meanwhile...the function which spawned the webworker sends an ajax request to the same webserver use the synchronous flag of the xmlhttprequest object(yes, it has a synchronous option). since it will block until the http request is complete, you can just have your webserver script poll the database for updates or whatever until the result has been sent to it.

    ugly, i know. but it would block without hogging cpu :D

    basically

    function get(...) {
        spawnWebworker(...);
        var xhr = sendSynchronousXHR(...);
        return xhr.responseTEXT;
    }
    
    0 讨论(0)
  • 2020-12-28 17:20

    When your async method starts, I would open some sort of modal dialog (that the user cannot close) telling them that the request is in process. When the request finishes, close the modal in your callback.

    One possible way to do this is with jqModal, but that would require you to load jQuery into your project. I'm not sure if that's an option for you or not.

    0 讨论(0)
  • 2020-12-28 17:27

    This is ugly, but anyway I think the question is kindof implying an ugly solution is desired...

    1. In your get function, serialize your query into a string.
    2. Open an iframe, passing (A) this serialized query and (B) a random number in querystring to this iframe
      • Your iframe has some javascript code that reads the SQL query and number from its own querystring
      • Your iframe asynchronously begins running the query.
      • When your iframe query is asynchronously finished, it sends it, along with the random number to a server of yours, say to /write.php?rand=###&reslt="blahblahblah"
      • Write.php saves this info somewhere
    3. Back in your main script, after creating and loading the iframe, you create a synchronous AJAX request to your server, say to /read.php?rand=####
    4. /read.php blocks until the written info is available, then returns it to your main page

    Alternately, to avoid sending the data over the network, you could instead have your iframe encode the result into a canvas-generated image that the browser caches (similar to the approach that Zombie cookie reportedly used). Then your blocking script would try to continually load this image over and over again (with some small network-generated delay on each request) until the cached version is available, which you could recognize via some flag that you've set to indicate it's done.

    0 讨论(0)
  • 2020-12-28 17:30

    No, you can't block until the asynch call finishes. It's that simple.

    It sounds like you may already know this, but if you want to use asynchronous ajax calls, then you have to restructure the way your code is used. You cannot just have a .get() method that makes an asynchronous ajax call, blocks until it's complete and returns the result. The design pattern most commonly used in these cases (look at all of Google's javascript APIs that do networking, for example) is to have the caller pass you a completion function. The call to .get() will start the asynchronous operation and then return immediately. When the operation completes, the completion function will be called. The caller must structure their code accordingly.

    You simply cannot write straight, sequential procedural javascript code when using asynchronous networking like:

    var result = abc.get()
    document.write(result);
    

    The most common design pattern is like this:

    abc.get(function(result) {
        document.write(result);
    });
    

    If your problem is several calling layers deep, then callbacks can be passed along to different levels and invoked when needed.


    FYI, newer browsers support the concept of promises which can then be used with async and await to write code that might look like this:

    async function someFunc() {
        let result = await abc.get()
        document.write(result);
    }
    

    This is still asynchronous. It is still non-blocking. abc.get() must return a promise that resolves to the value result. This code must be inside a function that is declared async and other code outside this function will continue to run (that's what makes this non-blocking). But, you get to write code that "looks" more like blocking code when local to the specific function it's contained within.

    0 讨论(0)
  • 2020-12-28 17:32

    Why not just have the original caller pass in a callback of its own to get()? This callback would contain the code that relies on the response.

    The get() method will forward the callback to providerGet(), which would then invoke it when it invokes its own callback.

    The result of the fetch would be passed to the original caller's callback.

    function get( arg1, arg2, fn ) {
        // whatever code
    
        // call providerGet, passing along the callback
        providerGet( fn );
    }
    
    function providerGet( fn ) {
        // do async activity
    
        // in the callback to the async, invoke the callback and pass it the data
        // ...
              fn( received_data );
        // ...
    }
    
    get( 'some_arg', 'another_arg', function( data ) {
        alert( data );
    });
    
    0 讨论(0)
提交回复
热议问题