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('http://hyperstruct.net'));
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);
}
}
Post new comment