CS 330 Lecture 38 – Promises
Agenda
- what ?s
- the event loop
- chaining asynchronous events
- callback hell
- parallelizing asynchronous events
- promises in JavaScript
TODO
- Some folks have asked for a few more opportunities for participation points. I will grant 3 extra credit participation points to any student who gives a semi-lightning talk and demo (5-8 minutes) during lecture next Wednesday on some contained and interesting programming language feature. You may work in pairs. Please express your interest and submit your topic before Monday. You need not be an expert on the subject; just be curious and do some investigation. Some topics I would strongly encourage you to report on include:
- JavaScript’s inheritance mechanism
- Actor-based program design
Lambdas in Java 8- Java’s Streams API
Intentions
- I recognize that a callback-driven system locks me into an imperative style of programming. I call some asynchronous operation that produces some side effect, but I cannot easily integrate this side effect into a pipelined process.
- Using promises, I can express unwieldy asynchronous callbacks as a sequence of dependencies, thereby avoiding callback hell.
Why Doesn’t This Work?
function getEmail(username) {
var address;
get('lookup?id=' + username, function onReceipt(usr) {
address = usr.address;
});
return address;
}
var body = '...';
var subject = '...';
var message = new Message(subject, body);
var username = '...';
message.sendTo(getEmail(username));
Code
slow_image.php
<?php
$color = $_REQUEST['color'];
$delay = $_REQUEST['delay'];
sleep($delay);
$path = "$color.png";
$f = fopen($path, 'rb');
header("Content-Type: image/png");
header("Content-Length: " . filesize($path));
fpassthru($f);
fclose($f);
?>
promise.html
<!DOCTYPE html>
<html>
<head>
<title>...</title>
</head>
<body>
<img src="" id="red"/>
<img src="" id="yellow"/><br/>
<img src="" id="green"/>
<img src="" id="blue"/>
<script>
/*
function loadInSequence() {
var img = document.querySelector('#red');
img.onload = function() {
console.log('red');
var img = document.querySelector('#yellow');
img.onload = function() {
console.log('yellow');
var img = document.querySelector('#green');
img.onload = function() {
console.log('green');
var img = document.querySelector('#blue');
img.onload = function() {
console.log('blue');
alert('all done!');
}
img.src = 'slow_image.php?color=blue&delay=4';
}
img.src = 'slow_image.php?color=green&delay=3';
}
img.src = 'slow_image.php?color=yellow&delay=2';
}
img.src = 'slow_image.php?color=red&delay=1';
}
loadInSequence();
*/
function load(color, delay) {
return new Promise(function(resolve) {
var img = document.querySelector('#' + color);
img.onload = function() {
console.log(color);
resolve();
}
img.src = 'slow_image.php?color=' + color + '&delay=' + delay;
});
}
// ----------------------------------------------------------------------------
// Load in sequence with promises
//load('red', 1)
// .then(function() {return load('yellow', 2);})
// .then(function() {return load('green', 3);})
// //.catch(function() {alert('this app broked!');})
// .then(function() {return load('blue', 4);})
// .then(function() {return alert('all done');})
// ----------------------------------------------------------------------------
// Load in parallel with promises
var promiseRed = load('red', 1);
var promiseYellow = load('yellow', 2);
var promiseGreen = load('green', 3);
var promiseBlue = load('blue', 4);
// Manually join...
// promiseRed
// .then(function() {return promiseYellow;})
// .then(function() {return promiseGreen;})
// .then(function() {return promiseBlue;})
// .then(function() {alert('all done!');})
// .catch(function() {alert("no!!!!")});
// Or use helper...
Promise.all([promiseRed, promiseYellow, promiseGreen, promiseBlue]).then(
function(result) { alert("okay"); },
function(error) { alert("uh oh: " + error); }
);
</script>
</body>
</html>
Haiku
on callback hell
Old Phoenix burned up
But he forgot to hit Next
No more phoenixes
Old Phoenix burned up
But he forgot to hit Next
No more phoenixes