promises are so passé - tim perry - codemotion milan 2016
TRANSCRIPT
![Page 1: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/1.jpg)
Promises ARESO PASSÉ
Tim Perry - @pimterry - Senior software engineer at resin.io
![Page 2: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/2.jpg)
![Page 3: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/3.jpg)
"Any fool can write code that a computer can understand.Good programmers write code that humans can understand."
— Martin Fowler
![Page 4: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/4.jpg)
LET'S TALK ABOUT
JavaScript
![Page 5: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/5.jpg)
Async
![Page 6: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/6.jpg)
JavaScriptREMOVES ASYNC CHALLENGES
BUTCAN'T DIRECTLY EXPRESS ASYNC
![Page 7: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/7.jpg)
JavaScriptREMOVES ASYNC CHALLENGES
![Page 8: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/8.jpg)
EVENT-DRIVENRUN-TO-COMPLETIONSINGLE-THREADING
![Page 9: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/9.jpg)
WE HAVE ANASYNCHRONOUS
ECOSYSTEM
![Page 10: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/10.jpg)
SIMPLERBUT NOT SIMPLE
![Page 11: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/11.jpg)
JavaScriptCAN'T DIRECTLY EXPRESS ASYNC
![Page 12: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/12.jpg)
WE NEEDHIGH-LEVEL ASYNC CONSTRUCTS
![Page 13: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/13.jpg)
Callbacks
![Page 14: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/14.jpg)
PATTERN: SEQUENTIAL DEPENDENT OPERATIONS
- Get the user from the database- Get that user's best friend- Get that best friend's profile picture- Add a mustache to everybody in the picture- Show the transformed picture on the page
![Page 15: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/15.jpg)
PATTERN: SEQUENTIAL DEPENDENT OPERATIONS
function mustachify(userId, callback) { loadUserFromDatabase(userId, function (err, user) { if (err) callback(err); else user.getBestFriend(function (err, friend) { if (err) callback(err); else friend.getBestPhoto(function (err, photo) { if (err) callback(err); else addMustache(photo, function (err, betterPhoto) { if (err) callback(err); else showPhotoToUser(user, betterPhoto, callback); }); }); }); });}
![Page 16: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/16.jpg)
PATTERN: CROSS-OPERATION ERROR HANDLINGfunction mustachify(userId, callback) { try { loadUserFromDatabase(userId, function (err, user) { if (err) callback(err); else { try { user.getBestFriend(function (err, friend) { if (err) callback(err); else { try { friend.getBestPhoto(function (err, photo) { if (err) callback(err); else { try { addMustache(photo, function (err, betterPhoto) { if (err) callback(err); else { try { showPhotoToUser(user, betterPhoto, callback); } catch (e) { callback(e) } } }); } catch (e) { callback(e) } } }); } catch (e) { callback(e) } } }); } catch (e) { callback(e) } } }); } catch (e) { callback(e) }}
![Page 17: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/17.jpg)
Promises
![Page 18: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/18.jpg)
PROMISES RECAP
A promise is a representation of a (potentially) ongoing process.▸ Pending▸ Fulfilled▸ Rejected
![Page 19: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/19.jpg)
PROMISES RECAP
Define a new promise:var p = new Promise(function (resolve, reject) { // ... Do some asynchronous things // Eventually call resolve or reject});
Promise.resolve({ myResult: 123 });
Promise.reject(new Error("BAD THINGS"));
![Page 20: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/20.jpg)
PROMISES RECAP
Chain promises together:loadData().then(function (data) { return transformData(data);}).then(function (transformedData) { showData(data);});
![Page 21: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/21.jpg)
PROMISES RECAP
Catch errors across steps:loadData().then(function (data) { return transformData(data);}).then(function (transformedData) { showData(data);}).catch(function (error) { console.log(error);});
![Page 22: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/22.jpg)
PROMISES RECAP
Combine promises:var allData = Promise.all([ loadData("company-one"), loadData("company-two")]);
var firstResponse = Promise.race([ getDataFromDataCenter1(), getDataFromDataCenter2()]);
![Page 23: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/23.jpg)
PROMISES ARE OURCURRENT BEST SOLUTION
![Page 24: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/24.jpg)
PROMISES STILL HAVETOO MUCH CEREMONY
![Page 25: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/25.jpg)
PROMISES STILLCOUPLE FUNCTION SCOPESWITH ASYNC OPERATIONS
![Page 26: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/26.jpg)
PATTERN: COMBINING SEQUENTIAL RESULTS
- Get the current user's data- Load the timeline for that user- Show the user's details & timeline on screen
![Page 27: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/27.jpg)
PATTERN: COMBINING SEQUENTIAL RESULTS
var user;getUser().then(function (userData) { user = userData; // <- Ick return getTimeline(user);}).then(function (timeline) { showUser(user); showTimeline(timeline);});
![Page 28: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/28.jpg)
PATTERN: ASYNC IN A LOOP
- For each task: - Run the task to completion - Add the result to the task results array - Move on to the next task- Return the array of task results
![Page 29: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/29.jpg)
PATTERN: ASYNC IN A LOOP
function runTasks(tasks) { var accumulatedPromise = Promise.resolve([]);
for (var task of tasks) { accumulatedPromise.then(function (accumulatedResults) { return task.run().then(function (result) { return accumulatedResults.concat(result); }); }); }
return accumulatedPromise;}
![Page 30: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/30.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
- If the server is up and the user's login is valid: - Save their data - Show a nice message
- Otherwise: - Show an error
![Page 31: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/31.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
isServerAvailable().then(function (serverIsAvailable) { return serverIsAvailable && isAuthenticationValid();}).then(function (canSave) { if (canSave) { return saveData().then(function () { showMessage("Data saved"); }); } else { showWarning("Couldn't save data"); }});
![Page 32: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/32.jpg)
PROMISES GIVE US AMODEL FOR ASYNC
PROCESSES
![Page 33: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/33.jpg)
BUT THEIR APIDOESN'T PLAY NICELY
WITH EXISTING CONSTRUCTS
![Page 34: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/34.jpg)
Generators
![Page 35: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/35.jpg)
GENERATORS ARE FUNCTIONS THATREPEATEDLY YIELD VALUES
![Page 36: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/36.jpg)
GENERATORS ARE FUNCTIONS THAT
PAUSE
![Page 37: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/37.jpg)
function* generateEveryNumber() { var n = 0; while(true) { yield n; n += 1; }}
![Page 38: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/38.jpg)
function* generateEveryNumber() { var n = 0; while(true) { yield n; n += 1; }}
var allNumbers = generateEveryNumber();
allNumbers.next(); // { value: 0, done: false }allNumbers.next(); // { value: 1, done: false }allNumbers.next(); // { value: 2, done: false }
![Page 39: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/39.jpg)
function* generateEveryNumber() { var n = 0; while(true) { yield n; n += 1; }}
for (var number of generateEveryNumber()) { if (number > 1000) break;
console.log(number); // 1, 2, 3 ... 1000}
![Page 40: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/40.jpg)
function* sumUpNumbers() { var accumulator = (yield);
while (true) { var nextAddition = (yield accumulator); accumulator += nextAddition; }}
var sum = sumUpNumbers();sum.next(); // Need an initial next(), to run to first yield.sum.next(1); // { value: 1, done: false }sum.next(5); // { value: 6, done: false }
![Page 41: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/41.jpg)
Promises +
Generators
![Page 42: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/42.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
- If the server is up and the user's login is valid: - Save their data - Show a nice message
- Otherwise: - Show an error
![Page 43: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/43.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
spawn(function* () { if ((yield isServerAccessible()) && (yield isAuthenticationValid())) { yield saveData(); showMessage("Data saved"); } else { showWarning("Couldn't save data"); }});
![Page 44: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/44.jpg)
WRAPPING A GENERATOR
function spawn(generatorConstructor) { var generator = generatorConstructor();
function step(input) { var result = generator.next(input); var value = Promise.resolve(result.value); if (result.done) return value; else return value.then(step); }
return step();}
// (Error handling omitted)
![Page 45: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/45.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
spawn(function* () { if ((yield isServerAccessible()) && (yield isAuthenticationValid())) { yield saveData(); showMessage("Data saved"); } else { showWarning("Couldn't save data"); }});
![Page 46: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/46.jpg)
PROMISES ARE DEADLONG LIVE PROMISES
![Page 47: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/47.jpg)
Async / Await
![Page 48: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/48.jpg)
ASYNC/AWAIT ISTHE SAME MAGIC
BUT BUILT IN
![Page 49: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/49.jpg)
PATTERN: CONDITIONAL ON ASYNC RESULT
async function save() { if ((await isServerAccessible()) && (await isAuthenticationValid())) { await saveData(); showMessage("Data saved"); } else { showWarning("Couldn't save data"); }}
![Page 50: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/50.jpg)
PATTERN: COMBINING SEQUENTIAL RESULTS
async function showUserAndTimeline() { var user = await getUser(); var timeline = await getTimeline(user);
showUser(user); showTimeline(timeline);}
![Page 51: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/51.jpg)
PATTERN: ASYNC IN A LOOP
async function runTasks(tasks) { var results = [];
for (task of tasks) { results.push(await task.run()); }
return results;}
![Page 52: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/52.jpg)
THIS ISNOT ALL ROSES
![Page 53: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/53.jpg)
GOTCHA: YOU STILL HAVE TO CATCH ERRORS
![Page 54: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/54.jpg)
ASYNC/AWAIT ERROR HANDLING
async function mustachify(userId) { var user = await loadUserFromDatabase(userId); var friend = await getBestFriend(user); var photo = await friend.getBestPhoto(); var betterPhoto = await addMustache(photo); return showPhotoToUser(user, betterPhoto);}
mustachify(userId).catch(function (error) { // You can still use catch() - it's promises under the hood});
![Page 55: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/55.jpg)
ASYNC/AWAIT ERROR HANDLING
async function mustachify(userId) { try { var user = await loadUserFromDatabase(userId); var friend = await getBestFriend(user); var photo = await friend.getBestPhoto(); var betterPhoto = await addMustache(photo); return showPhotoToUser(user, betterPhoto); } catch (error) { // Try/catch now works with promises & async too }}
mustachify(userId);
![Page 56: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/56.jpg)
GOTCHA: CAN'T AWAIT IN NESTED FUNCTIONS
async function getAllFriendNames() { var friendData = friendIds.map(function (friendId) { // This code isn't in an async function, // so this is a syntax error. return (await getUserData(friendId)); });
return friendData.map(function (friend) { return friend.name; });}
![Page 57: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/57.jpg)
GOTCHA: CAN'T AWAIT IN NESTED FUNCTIONS
async function getAllFriendNames() { var friendData = friendIds.map(async function (friendId) { return (await getUserData(friendId)); });
// Map() doesn't care about async, so our getUserData // calls haven't actually finished yet. return friendData.map(function (friend) { return friend.name; });}
![Page 58: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/58.jpg)
GOTCHA: CAN'T AWAIT IN NESTED FUNCTIONS
async function getAllFriendNames() { var friendData = await Promise.all( friendIds.map(function (friendId) { return getUserData(friendId); }) );
return friendData.map(function (friend) { return friend.name; });}
![Page 59: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/59.jpg)
GOTCHA: EASY TO OVERUSE AWAIT
![Page 60: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/60.jpg)
HOW DO YOUSTART USING THIS?
![Page 61: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/61.jpg)
Available in Chrome
Behind a flag in Edge
Coming in FireFox 52
Implemented in WebKit
![Page 62: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/62.jpg)
![Page 63: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/63.jpg)
THESE ARE OURHIGH-LEVEL ASYNC CONSTRUCTS
![Page 64: Promises are so passé - Tim Perry - Codemotion Milan 2016](https://reader031.vdocuments.us/reader031/viewer/2022030317/587081491a28ab57368b66b5/html5/thumbnails/64.jpg)
Promises ARESO PASSÉ
Tim Perry - @pimterry - Senior software engineer at resin.io