Synchronous invocation in JavaScript, part 3: returning values

We’ve seen how to simulate a blocking sleep() in JavaScript and what happens under the hood when we do.

Another scenario where a blocking call makes a big difference in terms of clarity is requesting data from the network and suspending execution until the answer arrives:


    var resume = proc(function() {
        dump("Retrieving URL...\n");
        var data = yield(getUrl(''));
        dump(data + '\n');
    });

getUrl() produces a pseudo-blocking function which, when invoked, sends an AJAX request and handles the response. “Handling the response” in this case means passing the received data back to the process driver.

We don’t really care about the implementation of getUrl() now, so it’ll use a fake ajaxRequest() internally; see bottom of post for an implementation that actually does something.


    function getUrl(url) {
        return function(driver) {
            sendAjaxRequest(url, function(response) {
                driver(response);
            });
        }
    }

The implementation of driver() we saw in the previous parts won’t allow passing values back to the process. That’s easy to fix, though: just turn process.next() into process.send(value) where value is whatever was passed to driver().


    function proc(processDef) {
        var process = processDef();

        function driver(value) {
            var partialComputation = process.send(value);

            partialComputation(advance);
        }

        return driver;
    }

Before, the pseudo-blocking call would call driver(), which would in turn call process.next(), causing execution of the process to be resumed from the line after yield().

Now, the pseudo-blocking call calls driver(value) instead. Inside the driver, that leads to the process.send(value) which passes control back to the process, where value becomes the return value of yield() and gets assigned to data. Execution finally resumes from the line after yield().

Here’s the working version of getUrl():


    function getUrl(url) {
        return function(driver) {
            var req = new XMLHttpRequest();
            req.open('GET', url, true);
            req.onreadystatechange = function(event) {
                if(req.readyState == 4)
                    driver(req.responseText);
            };
            req.send(null);
        }
    }

Articles in this series:

  1. Part 1: Problem and basic solution
  2. Part 2: Execution dissected
  3. Part 3: Returning values
  4. Part 4: Error handling