Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Asynchrony in JavaScript
Alper Sarikaya (@yelperalp)CS 638 JavaScript & Web Programming
November 17th, 2015
Asynchrony in JavaScript
How we handle it in JavaScript (and jQuery, D3, etc.)
Requesting data in JavaScript (and jQuery, D3, etc.)
Event Handling (and jQuery, D3, etc.)
Reactive Programming
WebSockets/binary data/WebGL
WebWorkers -
JavaScript is single-threaded!
This means:
Asynchronous events can return and interrupt
Long processing work can block interrupts from occurring (page appears to hang)
Only one thing can be done at a time(except if you use WebWorkers; more later)
Handling Asynchronicity
Want to (without reloading page):
Get data from datastore on the webserver
Update state on webserver based on user action
Post a message, record a vote for others to see
Retrieve some video/binary data to display to client
Handling Asynchronicity
Make an XmlHttpRequest (XHR)
Ajax programming model
Asynchronous JavaScript and XML
var xhr = new XMLHttpRequest();xhr.open('GET', 'DoSomething.php', true);xhr.responseType = 'json';
xhr.addEventListener('load', function() {if (xhr.status == 200) {
loadBinaryData(xhr.response);} else {
console.warning("failed to load (status: %d)", xhr.status);
console.trace();}
});
xhr.send(null);
var xhr = new XMLHttpRequest();xhr.open('GET', 'DoSomething.php', true);xhr.responseType = 'json';
xhr.addEventListener('load', function() {if (xhr.status == 200) {
loadJsonData(xhr.response);} else {
console.warning("failed to load (status: %d)", xhr.status);
console.trace();}
});
xhr.send(null);
Webserver does a task
Type of returned data
Do something with the returned data
Send the request
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
$.get('DoSomething.php', loadJsonData, 'json');
https://api.jquery.com/jquery.get/
$.get('DoSomething.php', loadJsonData, 'json');
https://api.jquery.com/jquery.get/
One success
Implement JavaScript operations in a cross-browser way
Syntactic sugar (do the same thing in less lines of code)
JavaScript ECMA 5 (basically HTML5) standardized a lot of the ugly old stuff
Dealing with returned data
$.get('DoSomething.php', loadJsonData, 'json');
Do something with the returned data
Dealing with returned data
Do something with the returned data
var dataReady = false;var ds = {};
$.get('DoSomething.php', loadJsonData, 'json');var loadJsonData = function(text) {dataReady = false;ds.data = [];
// process some data, fill up ds.data with text
// Set flag to allow rendering to continue.dataReady = true;
};
Dealing with returned data
Do something with the returned data
$.get('DoSomething.php', loadJsonData, 'json');$.get('DoSomethingElse.php', loadJsonData, 'json');var loadJsonData = function(text) {dataReady = false;ds.data = [];
// process some data, fill up ds.data with text
// Set flag to allow rendering to continue.// ???dataReady = true;
};
Dealing with returned data
Do something with the returned data
var loadJsonFile = function(text) {// process the data
continueIfDone();};
var continueIfDone = function() {// check that all data is loaded, if not:return false;
// otherwise, continuenextStep();
}
Use promises for one-time callbacks (built into ES6: http://www.html5rocks.com/en/tutorials/es6/promises/)
Use WebSockets for real-time connections (e.g. chat)(built into newer browsers, see https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications for an example)
Promises!
getJSON('story.json').then(function(story) {return getJSON(story.chapterUrls[0]);
}).then(function(chapter1) {console.log("Got chapter 1!", chapter1);
});
http://www.html5rocks.com/en/tutorials/es6/promises/
Promises!function get(url) {// Return a new promise.return new Promise(function(resolve, reject) {// Do the usual XHR stuffvar req = new XMLHttpRequest();req.open('GET', url);
req.onload = function() {// This is called even on 404 etc// so check the statusif (req.status == 200) {// Resolve the promise with the response textresolve(req.response);
}else {// Otherwise reject with the status text// which will hopefully be a meaningful errorreject(Error(req.statusText));
}};
// Handle network errorsreq.onerror = function() {reject(Error("Network Error"));
};
// Make the requestreq.send();
});}
Processing Data
Very convenient to deal with JSON dataJust set returnType json
arraybuffer
{"VHA4_P11_F21_DPI3-ref": {"attenuation":
"readBreadth.dat","metrics": "conjProbDiff.dat","numReads": 258000,"reference": "VN1203-HA.fa.txt"
},"VHA3_P1_F991_DPI3-ref": {"attenuation":
"readBreadth.dat","metrics": "conjProbDiff.dat","numReads": 295000,"reference": "VN1203-HA.fa.txt"
}}
var xhr = new XMLHttpRequest();xhr.open('GET', 'DoSomething.php', true);xhr.responseType = 'json';
xhr.addEventListener('load', function() {if (xhr.status == 200) {
loadJsonData(xhr.response);} else {
console.warning("failed to load (status: %d)", xhr.status);
console.trace();}
});
xhr.send(null);
Bind to event!
Event Listeners
Event Listeners
Events can be:
Monitoring AJAX progress events (see Monitoring Progress on MDN)
User input (mouseover, mousemove, key-press)
Custom-built events (e.g. when a rendering pass finishes)
Applications?
Validating formsAre all parameters within acceptable values?
Navigating page with keystrokesEver typed in ? into Twitter or Gmail?
Capture user inputUser can drive a WebGL game, drag DOM elements, etc.
<button id="submit" type="submit">Submit Form</button>
Event Listeners
var submitButton = document.getElementById("#submit");
submitButton.addEventListener("click", parseForm);
HTML
JS
<button id="submit" type="submit">Submit Form</button>
Event Listeners (jQuery)
$("#submit").click(parseForm);
HTML
JS
<div id="container"><button id="submit" type="submit">Submit Form</button>
</div>
Multiple Event Listeners in DOM
$("#submit").click(parseForm);$("#container").click(doSomethingElse);
HTML
JS
parseForm() called
doSomethingElse() called
<div id="container"><button id="submit" type="submit">Submit Form</button>
</div>
Multiple Event Listeners in DOM
$("#submit").click(parseForm);$("#container").click(doSomethingElse);var parseForm = function(event) {event.stopPropagation();// pull data from the form, and parse
};
HTML
JS
Alternatives?
Reactive programming style (Rx)See https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 for a great intro
Asynchrony Potpourrivar dataWorker = new Worker('worker.js');dataWorker.postMessage(numPoints);console.log("sent message");
dataWorker.onmessage = function(e) {console.log("received response");
};WebWorkers uses a message-passingsystem to offload computation intoa separate thread.This gets around the UI hanging issuewhen processing data!
onmessage = function(e) {var numPoints = e.data;// do some computation
postMessage(['databuf', returnData], returnData);}worker.js
Asynchrony Potpourrivar xhr = new XMLHttpRequest();xhr.open('GET', filename, true);xhr.responseType = 'arraybuffer';
xhr.addEventListener('progress', updateProgress(name), false);
xhr.addEventListener('load', function() {if (xhr.status == 200) {loadBinaryData(xhr.response, name);
} else {console.warning("failed to load (status: %d)", xhr.status);console.trace();
}});
xhr.send(null);
Binary data DataView
or natively with WebGL data buffers
Asynchrony Potpourri
function webGLStart() {var canvas = document.getElementById("lesson01-canvas");initGL(canvas);initShaders();initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);gl.enable(gl.DEPTH_TEST);
drawScene();}
WebGL uses commands sent to the GPU, and eventually fires
Asynchrony Potpourri
function tick() {window.reqeustAnimationFrame(tick);handleKeys();drawScene();animate();
}
RequestAnimationFrame requeststhe browser to call the animationloop as soon as it is able
Asynchrony Potpourri
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]);
exampleSocket.send("Here's some text that the server wants!");
exampleSocket.onmessage = function (event) {console.log(event.data);
}
WebSockets use TCP connectionsto send and receive data(think chat applications, real-time connection to server applications...)