rangle.io The Web Inverted www.rangle.io @rangleio 150 John St., - - PowerPoint PPT Presentation

rangle io
SMART_READER_LITE
LIVE PREVIEW

rangle.io The Web Inverted www.rangle.io @rangleio 150 John St., - - PowerPoint PPT Presentation

rangle.io The Web Inverted www.rangle.io @rangleio 150 John St., Suite 501 Toronto, ON Canada M5V 3E3 1-844-GO-RANGL PROMISE-BASED ARCHITECTURE Yuri Takhteyev CTO, rangle.io rangle.io @Qaramazov The Web Inverted yuri


slide-1
SLIDE 1

@rangleio www.rangle.io

150 John St., Suite 501
 Toronto, ON Canada
 M5V 3E3 1-844-GO-RANGL

rangle.io

The Web Inverted

slide-2
SLIDE 2

rangle.io

The Web Inverted

PROMISE-BASED ARCHITECTURE

CTO, rangle.io

Yuri Takhteyev

Some rights reserved - Creative Commons 2.0 by-sa, image credits on last slide.

@Qaramazov yuri

http://yto.io/xpromise2

slide-3
SLIDE 3

Why are Promises Awesome?

The answer isn’t always obvious even to die-hard fans!

slide-4
SLIDE 4
  • JavaScript can’t wait
  • All solutions are variations on

callbacks.

Asynchronicity

slide-5
SLIDE 5

Node-Style Callbacks

request(url, function(error, response) { // handle success or error. }); doSomethingElse();

slide-6
SLIDE 6

The Pyramid of Doom

queryTheDatabase(query, function(error, result) { request(url, function(error, response) { doSomethingElse(response, function(error, result) { doAnotherThing(result, function(error, result) { request(anotherUrl, function(error, response) { ... }) }); }) }); });

And hard to decompose. Why is it so messy? Because we have to provide the handler
 at the time of the request.

slide-7
SLIDE 7

Promises

// Then add another handler. promise.then(function(response) { // handle the same response again. }); // Then add a handler. Maybe in // another place. promise.then(function(response) { // handle the response. }); // handle the response. var promise = $http.get(url);

slide-8
SLIDE 8

Promises as Wrappers

  • Pass around promises instead of passing around values.
  • In other words, write functions that receive promises

and return promises.

slide-9
SLIDE 9

General Model

value 1 function value 2 promise 1 function promise 2

use .then() to create a new promise

slide-10
SLIDE 10

Groking Promises

Promises can be unintuitive, until you grok some basic axioms.

slide-11
SLIDE 11

Chained Promises Can Get Ugly

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }) .then(null, function(error) { $log.error(error); });

Slides are at http://yto.io/xpromise2

slide-12
SLIDE 12

Let’s Figure It Out

var errorHandlerPromise = vmUpdatePromise.then(null, function(error) { $log.error(error); }); var responsePromise = $http.get('http://example.com/api/v1/tasks'); var tasksPromise = responsePromise.then(function(response) { return response.data; }); var filteredTasksPromise = tasksPromise.then(function(tasks) { return filterTasksAsynchronously(tasks); }); var vmUpdatePromise = filteredTasksPromise.then(function(tasks) { $log.info(tasks); vm.tasks = tasks; })

slide-13
SLIDE 13

Axiom: .then() Returns a Promise. Always.

var dataPromise = getDataAsync(query); var transformedDataPromise = dataPromise .then(function (results) { return transformData(results); });

transformedDataPromise will be a promise regardless of what transformedData does.

slide-14
SLIDE 14

When the callback… then .then() returns a promise that… returns a regular value resolves to that value. returns a promise resolves to the same value throws an exception rejects with the exception

slide-15
SLIDE 15

Catching Rejections

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }, function(error) { $log.error(error); });

slide-16
SLIDE 16

Catching Rejections

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }, function(error) { $log.error(error); });

slide-17
SLIDE 17

Catching Rejections

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }, function(error) { $log.error(error); });

Nobody hears you scream…

slide-18
SLIDE 18

Catching Rejections

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }, function(error) { $log.error(error); });

Nobody hears you scream…

slide-19
SLIDE 19

Better

$http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }) .then(function(tasks) { return filterTasksAsynchronously(tasks); }) .then(function(tasks) { $log.info(tasks); vm.tasks = tasks; }) .then(null, function(error) { $log.error(error); });

slide-20
SLIDE 20

Or Pass the Buck

return $http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; });

slide-21
SLIDE 21

Making Promises

You rarely need to do this. But it’s best to know how.

slide-22
SLIDE 22

Avoid $q.defer. Denodeify.

var getFooPromise = denodeify(getFooWithCallbacks); return getFooPromise() .then(function(result) { // do something with the result. });

https://github.com/rangle/angular-promisify

slide-23
SLIDE 23
  • $q.when(x): Returns a promise that resolves to x.
  • $q.reject(e): Returns a promise that rejects with e.

Trivial Promises

slide-24
SLIDE 24

Do’s and Don’ts

Things to do and things not to do.

slide-25
SLIDE 25

Promise Chains Considered Harmful

function getTasks() { return $http.get('http://example.com/api/v1/tasks') .then(function(response) { return response.data; }); } function getMyTasks() { return getTasks() .then(function(tasks) { return filterTasks(tasks, {

  • wner: user.username

}); }); }

slide-26
SLIDE 26
  • A function that returns a promise should always return a

promise and should never throw.

  • Return $q.reject(error) instead of throwing.
  • Wrap non-promise return values in $q.when().

Stay Consistent

slide-27
SLIDE 27
  • If you are not sure whether your operation will eventually be

synchronous or not, assume asynchronous and return a promise.

When in Doubt, Return a Promise

slide-28
SLIDE 28
  • A function that receives a promise, should normally return a

promise, only handling those errors that it is equipped to

  • handle. Your caller can figure out how to handle rejections.
  • If you do not return a promise, though, then you gotta

handle the errors.

Pass the Buck, But Don’t Drop it

slide-29
SLIDE 29
  • Avoid code that assumes that something has already

happen.

  • Instead, ask for a promise, return a promise.
  • If you do write such code, name your functions to

communicate this.

Avoid Optimistic Code

slide-30
SLIDE 30

Neat Things We Can Do with Promises

Promises can be unintuitive, until you grok some basic axioms.

slide-31
SLIDE 31

Promise Caching

var tasksPromise; function getTasks() { taskPromise = taskPromise || getTasksFromTheServer(); return taskPromise; }

slide-32
SLIDE 32

Prefetching

var tasksPromise = getTasksFromTheServer(); function getTasks() { return taskPromise; }

slide-33
SLIDE 33

Postponing Requests

function get(path) { return user.waitForAuthentication() .then(function() { return $http.get(path); }) .then(function(response) { return response.data; }); };

slide-34
SLIDE 34

Functional Composition with Promises

var R = require('ramda'); var getExifDate = R.pPipe( getExifData, // returns a promise R.prop('exif'), // a synchronous function R.prop('DateTimeOriginal') // same here ); getExifDate('/path/to/file.jpg') .then(function(date) { // Do something with the date. }) .then(null, $log.error);

slide-35
SLIDE 35

Koa-Style Generator Magic

app.use(function* () { var data = yield getPromiseForData(); // Proceed to use data console.log(data.items); });

slide-36
SLIDE 36

rangle.io

The Web Inverted

CTO, rangle.io

Yuri Takhteyev

THANK YOU!

@qaramazov yuri

slide-37
SLIDE 37

Image Credits

by jbrazito by Quinn Dombrowski

slide-38
SLIDE 38

Promises vs Events

Occasionally promises are not the answer.

slide-39
SLIDE 39

Promises Events (aka “Publish – Subscribe”) Things that happen ONCE Things that happen MANY TIMES Same treatment for past and future Only care about the future* Easily matched with requests Detached from requests