SlideShare a Scribd company logo
1 of 58
Download to read offline
I’m POSTAL For PROMISES

@

2014

by: Christian Lilley

about.me/xml

Thursday, January 16, 14

@xmlilley
Intro to Promises on my
blog: christianlilley.com

Thursday, January 16, 14

We're going to move really fast today, but if you want to go in depth, I’ve got some training slides on my blog.
• If you're at ng-conf, chances are, you've at least SEEN promises. They're those weird things you have to
extract your data from when they come out of the $http service, right? So, why do they exist?
UNCERTAINTY
ASYNC

Thursday, January 16, 14

• If you've heard of them, you've probably heard that they're about async. Which is true. But that significantly
understates their usefulness. Really, they’re designed in a way that lets them be about the bigger, more general
idea of uncertainty. About being able to crystallize uncertainty about time, space, user-based uncertainty or
almost anything, into a nice neat package, put a bow on it, and give it a super-useful API that provides us with a
gorgeous interaction pattern, that allows you to reason about and make DECISIONS about uncertainty throughout
your application.
BRAINS!!!!

Thursday, January 16, 14

• and they're about helping you make the most of your brain when dealing with that uncertainty. Promises
make engineer brains work better. Zombie approved.
Thursday, January 16, 14

But even though promises ARE about way more than just async, the truth is its what justifies their existence, so
let’s talk async.
In the beginning was the Word, and the Word was Callback, and the Callback was...
meh.

Thursday, January 16, 14
Callbacks: Strengths
They make Non-Blocking I/O possible.
You know how to use them.
</strengths>

Thursday, January 16, 14

Look, callbacks do the job: they make non-blocking I/O possible, and everybody knows how to use them. But...
Callbacks/CPS
NOW, NOW, NOW, NOW, NOW, NOW, NOW
No API for further interaction
No API for crossing contexts
Doesn’t Scale: works fine for 1,
horrible for more
Monolithic Handlers that break your

Thursday, January 16, 14

... they don't scale. They lead us towards huge, monolithic handler functions that try to do everything all at once,
and an attitude towards async that it's something you want to do as little of as possible and get it out of the way.
step1(value1,	
  function	
  (output)	
  {
	
  	
  	
  	
  step2(output1,	
  function(output2)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  step3(output2,	
  function(output3)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  step4(output3,	
  function(output4)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  Do	
  something	
  with	
  value4,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  quick,	
  before	
  it	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  disappears!!!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  });
});

Thursday, January 16, 14

When you start trying to stack a complex operation with callbacks, things get ugly, and nested, and complex, and
unreadable really quickly. We haven’t even put anything into these handler functions yet, and they’re already a
mess. See this shape forming here on the left? You know what this shape is called?
PYRAMID
OF
DOOOM!!!!

Thursday, January 16, 14

In the PYRAMID of DoOOOOM, we need to do everything RIGHT NOW, because in a second, it's going to be gone.
Forget about coming back and picking up later where you left off. And forget about that code being intuitive and
readable and clear and maintainable.
var	
  step1Started	
  =	
  true;
step1(value1,	
  callback1);
var	
  step1State	
  =	
  false;
function	
  callback1(data)	
  {
	
  	
  step1State	
  =	
  true;
	
  	
  step1Data	
  =	
  data;
	
  	
  doSomethingWithStep1Data();
}
.... later ....
if (step1State && step1Data) {
doSomethingElseWithStep1();
}
Thursday, January 16, 14

•And if you do invade the PYRAMID of DoOOOOM, and try to implement something that does let you leave off in
the middle of the pyramid and come back later, you’re going to start building boilerplate like this, caching state
variables and outputs, and adding either timers or events to trigger downstream actions.
•It works, but good luck with interop with other modules you didn't write, and good luck passing sequenced
instructions back and forth between scopes that don't all exist yet, and hence can't listen for events.
step1(value1,	
  callback1);

step2(value2,	
  callback2);

var	
  step1State	
  =	
  false;
function	
  callback1(data)	
  {
	
  	
  step1State	
  =	
  true;
	
  	
  step1Data	
  =	
  data;
	
  	
  doSomethingWithStep1Data();
}
.... timer... later ....
if (step1State && step1Data) {
doSomethingElseWithStep1();
}

var	
  step2State	
  =	
  false;
function	
  callback2(data)	
  {
	
  	
  step2State	
  =	
  true;
	
  	
  step2Data	
  =	
  data;
	
  	
  doSomethingWithStep2Data();
}
.... timer... later ....
if (step2State && step2Data) {
doSomethingElseWithStep2();
}

step3(value3,	
  callback3);

step4(value4,	
  callback4);

var	
  step3State	
  =	
  false;
function	
  callback3(data)	
  {
	
  	
  step3State	
  =	
  true;
	
  	
  step3Data	
  =	
  data;
	
  	
  doSomethingWithStep3Data();
}
.... timer ... later ....
if (step3State && step3Data) {
doSomethingElseWithStep3();
}

var	
  step4State	
  =	
  false;
function	
  callback4(data)	
  {
	
  	
  step4State	
  =	
  true;
	
  	
  step4Data	
  =	
  data;
	
  	
  doSomethingWithStep4Data();
}
.... timer ... later ....
if (step4State && step4Data) {
doSomethingElseWithStep4();
}

Thursday, January 16, 14

And if you want try that with all four of the tasks from that PYRAMID of DoOOOOM, you get this. Mind you, all this
junk doesn’t even include any error or success handlers yet. This is JUST what you need to have to be able to talk
reasonably about whether these four async functions have fired yet, whether they’ve returned yet, and whether
you can do anything useful with their data yet. And NONE of this code is making your application do anything yet.
It’s all just a bunch of imperative-style housekeeping that’s hard enough to keep track of and maintain, and even
harder to reason about and extend.
Promises to the
rescue.

Thursday, January 16, 14
Thursday, January 16, 14

Let's be clear: promises are not a technical innovation in the javascript execution engine. They don't make
anything happen more quickly. They don't execute async operations with different native code. Promises are all
about the brains of programmers, the same reason we do automated testing & TDD, talk about principles like
'single responsibility' and 'least surprise'.
The promise pattern is about making engineers more efficient, enabling them to actually reason about async
sensibly. It allows you to look at async stuff and uncertain stuff, visualize it, and write efficient code AS IF it were
predictable, consecutive synchronous operations. And to link those operations together in virtuous cycles or
flows.
And again, what
promises are not:

Thursday, January 16, 14

• So, if all that’s true, the naiive understanding of promises needs to go out the door:
action(target,
callback, error)
!==
action(target).then(
callback, error)
Thursday, January 16, 14

Promises are NOT simply a syntax replacement for callbacks. There wouldn't be any point in Promises if that was
all there was to it.
Promises are just a
“replacement for
callbacks”...
...if internal
combustion was just
a “replacement for
horses.”
Thursday, January 16, 14

Used right, Promises are a qualitative change, a fundamental shift in how we compose and plan for uncertainty
and sequencing.
So how about an example.
IMPERATIVE

------->

DECLARATIVE

Thursday, January 16, 14

How about if, instead of all that boilerplate I just showed you, what if you could just DECLARE what you want to
have happen? That you want a bunch of uncertain things to happen in a certain sequence, based on some other
uncertain things?
step1.
then(step2).
then(step3).
then(step4)

Thursday, January 16, 14

How about that? Welcome to declarative async and uncertainty with promises.
step1(value1,	
  callback1);

step2(value2,	
  callback2);

var	
  step1State	
  =	
  false;
function	
  callback1(data)	
  {
	
  	
  step1State	
  =	
  true;
	
  	
  step1Data	
  =	
  data;
	
  	
  doSomethingWithStep1Data();
}
.... timer... later ....
if (step1State && step1Data) {
doSomethingElseWithStep1();
}

var	
  step2State	
  =	
  false;
function	
  callback2(data)	
  {
	
  	
  step2State	
  =	
  true;
	
  	
  step2Data	
  =	
  data;
	
  	
  doSomethingWithStep2Data();
}
.... timer... later ....
if (step2State && step2Data) {
doSomethingElseWithStep2();
}

step3(value3,	
  callback3);

step4(value4,	
  callback4);

var	
  step3State	
  =	
  false;
function	
  callback3(data)	
  {
	
  	
  step3State	
  =	
  true;
	
  	
  step3Data	
  =	
  data;
	
  	
  doSomethingWithStep3Data();
}
.... timer ... later ....
if (step3State && step3Data) {
doSomethingElseWithStep3();
}

var	
  step4State	
  =	
  false;
function	
  callback4(data)	
  {
	
  	
  step4State	
  =	
  true;
	
  	
  step4Data	
  =	
  data;
	
  	
  doSomethingWithStep4Data();
}
.... timer ... later ....
if (step4State && step4Data) {
doSomethingElseWithStep4();
}

Thursday, January 16, 14

Instead of you writing all this boilerplate just to sequence 4 async operations across your application, and be able
to come back and interact with them later...
step1.
then(step2).
then(step3).
then(step4)

Thursday, January 16, 14

... all you need is this. This is how the promise pattern sequences things. It knows when it’s allowed to move
forward between steps, and keeps everything in order.
Or, decompose
them...

Thursday, January 16, 14
as1 = step1();
as2 = as1.then(step2);
as3 = as2.then(step3);
as4 = as3.then(step4);

Thursday, January 16, 14

And we can decompose that chain of operations incredibly easily, just by storing a reference to the promises for
each stage of that sequence. The promises are the variables on the left. These actions will still fire in the same
order as the previous example, but now we can start additional actions, later, whenever and wherever we want,
from any point in the middle of the sequence, using the data that comes out of those operations.
$HTTP

Thursday, January 16, 14

It’s like having DVR, for your async operations. And we can even pass these references into other contexts of the
application, without those contexts needing to know anything at all about the process that generated the promise.
And if you need
parallelism...

Thursday, January 16, 14

What if you want to have three of them run in parallel instead of in sequence, and have the fourth one kick in only
when all three are done?
as4 =
		$Q.all([as1, as2, as3])
		.then(step4)

Thursday, January 16, 14

Either, you write all the imperative boilerplate and state variables and other junk we saw before, THEN set a timer
to check every few ms to see if they’re all done yet, or use events if you’re lucky... all that OR you do this one line
that replaces all of that. That’s composition with promises. That’s the pattern they allow you to work with. So, if
that’s the overall pattern, how should we understand the component promise objects themselves?
So, in a nutshell, a
promise object
itself is...

Thursday, January 16, 14

So... I promised a certain metaphor in my talk title, even though we don’t have time for all the details here. But at
root, understand that a promise is basically just a mailbox.
Thursday, January 16, 14

It’s a special, standardized repository where you can stash the data that outputs from an operation, it has a
property representing the completion and success state of the operation, and it has utilities for leveraging that
knowledge into further operations. And all your functions can have a key to this mailbox, so they know what’s
going on. You can even pick this mailbox up and carry it around with you by reference into different contexts of
your app, providing your components with all the benefits of async, without needing to understand
implementation.
If the Promise is the
mailbox, then the Deferred:
Is the Postman.

Thursday, January 16, 14

Then, there’s this thing called the deferred. Lots of folks get Promises but have trouble with the Deferred object.
But it’s really straightforward once you think of the promise as a mailbox. The deferred is simply the postman.
No, not that
one, thank
God...

Thursday, January 16, 14

No, not THAT endless tribute to Kevin Costner’s vanity, thank god.
If the Promise is the
mailbox, then the Deferred:
Is the Postman.
The Postman is the only one who’s
allowed to:
Assign you a new mailbox.
(ie. create a promise)
Put new packages into the
mailbox. (resolve the promise)
Raise the little flag on the
side. (set state of the promise)
Thursday, January 16, 14

Just like with actual postal workers the postman is the only one who’s allowed to: Assign you a new P.O. Box, put
new packages into the mailbox, and, inverting the real life example, let’s pretend the little flag on the side of the
mailbox is used to show the box has incoming mail, not outgoing mail.
With the deferred, you’re the postman, and you can create and administer the mailbox. Without the deferred,
you’re a customer, a promise-consumer.
But it’s the pattern
that matters most...

Thursday, January 16, 14

That’s the main idea. But the pattern of use is more significant than the individual promise objects themselves.
Alone, they’re just syntactic sugar.
DECLARATIVE, NOT IMPERATIVE.
A UNIVERSAL API for uncertainty about
time & place.
An abstraction for any operation that
has happened or will happen.
A proxy for a remote object, which
allows you to abstract away all the
complexity of going and getting it.
A zero-boilerplate API for interacting
with the state, data, timing &
sequence of complex operations.
Thursday, January 16, 14

Together, they can change your whole approach to composition, and they can sure as hell reduce the amount of
code you write.
NOT JUST FOR ASYNC

Thursday, January 16, 14

Now, remember, PROMISES ARE NOT JUST FOR ASYNC.
userRegistered.then()
tutorialComplete.then()
purchaseSuccessful.then()
profileLocated.then()
etc...

Thursday, January 16, 14

Time and place uncertainty are certainly the conventional context for promises. But there are other kinds,
especially user-related uncertainty. A given AJAX request is actually semi-predictable, within a range. Users,
though, are totally unpredictable. You have no idea when - or if - your user will get around to doing certain
things, or in what order. Take advantage of promises as a way to encapsulate and abstract this kind of sequencing
uncertainty as well, even though it’s not execution engine asynchronousness in the way we mean that term. But
using promises, you can build custom async interfaces around user uncertainty.
Thursday, January 16, 14

Which brings us to Angular. Angular is an example of what happens when you start thinking in promises,
structurally. When you bake them right into the fabric of the application and use them as a way to model process
flows and make sure that the right things happen in the right place at the right time, so the different parts of your
application can hand-off those flows seamlessly, and customize them.
If you think that Misko and Vojta and Igor and Brian and Brad and all the other cats on the angular team are pretty
smart, if you're HERE, in other words, then follow their example and get way into promises.
1. Consume promises returned by
essential built-in Services.
$http
$timeout
$interval

Thursday, January 16, 14

Here’s sort-of an 8-step program to using promises in Angular.
Step 1: When you get started with promises, you’ll just consume them, from built-in services that return promises.
$http.... and very notably $timeout and $interval.
Angular has gone to the trouble to make all of the most fundamental async functions into promise generators, so
that Promises can be the seamless common API for all async.
var promise=
$http.get(‘URL’)
promise.then(doSomething);
promise.then(doThing2);
promise.then(doThing∞);

Thursday, January 16, 14

It’s as simple as this: if $http returns a promise, all you have to do is store a reference to that promise. Forever
after, for as long as you hold that reference, you can run other operations against it.
2. $resource calls
now return promises (in 1.2),
& $resource objects *have* one.

(Aren’t one. Have one.)

Thursday, January 16, 14

Step 2, when you’re ready to get a little tricky, try $resource. (The implementation of $resource has shifted quite a
bit in the past, but here’s the 1.2 skinny:)
$resource works a little differently than $http, but is nonetheless promise-style processing, via a useful, but
perhaps confusing, pattern: $http.get() returns a simple *promise*. But calling the initial .get() method on a
$resource type that you’ve defined, returns a... *resource object*, which itself *has* a promise. It Isn't one. But it
has one, as a property.
var bob =
resourceType.get({params})
// returns...

Resource {$promise: Object,
$resolved: true, $get:
function, $save: function,
$query: function…}
// after that...

bob.$promise.then(doStuff)
Thursday, January 16, 14

* To chain from that $resource with .then(), just use resourceObject.$promise
• Note that the reference is circular. So, if you unwrap a $resource's $promise object, what you get back is the
original $resource. Which, of course, still has a $promise. Which you can unwrap. So, the $resource has a
$promise which has a $resource which has a $promise...
credit:
substack/stream-handbook
Thursday, January 16, 14

Truly, it’s turtles all the way down.
Complicating things further, the other instance methods on a $resources, like $save(), they don’t modify that
original promise, instead they return a new bare $promise for the state of the operation, rather than the $resource
itself.
3. $route:resolve

(Integrating the promise architecture
so cleanly that controllers can be
fully ignorant of it.)

Thursday, January 16, 14

Step 3 is such a big, worthwhile feature that one of the release candidates for the version of Angular it debuted in
was named 'promise-resolution'.
$routeProvider
	 .when('/dashboard', {
	 	 templateUrl: 'URL',
	 	 controller: 'Ctrl',
	 	 resolve: {myData:
	 	 	 ['myService', function(myService)
	 	 	 	 {return
myService.get('URL', {params}).$promise
	 	 	 	 }]
		}

Thursday, January 16, 14

Using the :resolve property in the route, you get several huge benefits that you just don’t want to be operating
without. 1. the route won’t change until your data has been obtained, and you have everything you need to render
the view. No flicker, nothing looks broken. 2. Your controller gets to be totally, completely ignorant of
implementation. It doesn’t need to know what a promise is. It doesn’t need to know how to unwrap it, or check the
success of the operation. $routeProvider does all of that for you. All the controller gets is a data object, injected at
creation time, so it gets to be totally implementation independent.
angular.module('myApp')
	 .controller('Ctrl',
	 	 	 function(myData) {
	 	 	 	 	 	 // do stuff with myData
	 	 	 	 	 	 $scope.myData = myData;
	 	 	 })

Thursday, January 16, 14

And so then, in the controller, all you have to do is inject the name of the property, and you can do whatever you
want with it, like bind it to the $scope.
4. Note:
Automatic unwrapping in views:
GONE in 1.2

(Too much magic.)

Thursday, January 16, 14

Step 4 is just: be aware of a big recent change in Angular 1.2. For a little while there, we could place a promise
object on the $scope, and angular would automagically extract the value from it and inject *that* into the view.
Yadda yadda yadda, reading the repo, it seems it was just too much magic for people. It made consumers of
promises less aware of how they worked and how to use them. It was also slow. So, that feature, which you might
see in old documentation on the web, is gone now.
Alternatives:
Either inject your promises
via :resolve, so they’re autounwrapped, or...
promise.then(function(value)
{$scope.value = value})

Thursday, January 16, 14

Your Alternatives are clear and easy: Either inject promises with the :resolve property if you like magical
unwrapping, or just unwrap ‘em yourself.
5. Create your own promises
with $Q.

(Just like Q.js, only smaller.)

Thursday, January 16, 14

Step 5, start creating your own promises with $Q. Check out my detailed slides for more on how to do that.
6. Third-party libraries
like angular-ui-bootstrap
are built on promises, too.

(Great example of workflow:
ng-modal.)

Thursday, January 16, 14

Step 6: Start noticing how many Third-Party Implementations, like UI-Bootstrap Modal also take advantage of
promise flows.
$scope.modalOpen = function () {
var modalConfigs = {
templateUrl: ...,
controller: ...,
scope: $scope,
resolve: {
specialData: function ()
	
{return $http.get(‘/somedata’);}
	 	 }
	 }
var modalInstance =
	 	 $modal.open(modalConfigs);
	 modalInstance.result.then(handlerFunc);
};

// Inside the modalInstance: result.resolve();
Thursday, January 16, 14

When you define a modal instance, which carries a promise, you immediately define a handler, with
modalInstance.result.then(). Before we’ve even had time to do anything with that modal, we’ve already created a
handler for whatever we’re going to eventually return from the modal dialog as the result object. We don’t know
when or if there will be a return. But we’re ready for it, we can reason about it. And we can easily hand off to some
other consumer as well.
ALSO: UI-Modal uses its own :resolve property, just like the Angular router does, to ensure that the view won’t be
rendered until the data is ready.
7. Wrap a promise in
an Angular Service, and
you have a *Lazy Promise*.

(With lazy promises, time is now
fully irrelevant. Point and shoot.)

Thursday, January 16, 14

Step 7: promises that you can reference without needing to care if they even exist yet, let alone if they’ve resolved.
Normally, you need to know that a promise has been instantiated before you start interacting with it. But because
Angular services are instantiated lazily, as needed, and persist throughout application lifecycle, a Promise
wrapped in a service can be referenced at any time, from any location, provided you inject the service. The caller
of the promise need not know or care anything about the implementation.
function getDivision(divisionName) {
if (!divisionObjects[divisionName])
{
divisionObjects[divisionName] =
$http.get(baseUrl + divisionName)
.error(function(data, status) {
console.error('getDivision
failed, error:' + status)
});
} else {
return
divisionObjects[divisionName];
}
}
Thursday, January 16, 14

• Outside of Angular (or if you want multiple promises in one service) you can do the same thing, using a simple
getter function that will return an existing promise if available, or create a new one if not.
8. Interceptors
(and the rest of
the $http lifecycle)

(Great for loaders, other inline
transformations.)

Thursday, January 16, 14

Step 8: is Master-level! HTTP interceptors are these awesome things that allow you to mess around with every
single AJAX operation that goes in or out of your application, all from a single location. And they’re promised
based... in BOTH DIRECTIONS, in and out, request and response. Promises, again, aren't just something for async
output. They’re part of the modeling of the $http cycle from the very beginning, and you can thus chain even
before an async operation kicks off, perhaps executing another async operation before the main one is even
allowed to start.
$httpProvider.interceptors.push(function($q, $rootScope) {
return {
'request': function(config) {
$rootScope.$broadcast('asyncLoadStart');
return config || $q.when(config);
},
'requestError': function(rejection) {
$rootScope.$broadcast('asyncLoadEnd');
return $q.reject(rejection);
},
'response': function(response) {
$rootScope.$broadcast('asyncLoadEnd');
return response || $q.when(response);
},
'responseError': function(rejection) {
$rootScope.$broadcast('asyncLoadEnd');
return $q.reject(rejection);
}
};
})
Thursday, January 16, 14

This example is stripped bare and over-simplified, just so it fits on-screen. It shows a way to trigger an automatic,
universal loader screen for your app. With promises, we’re able to interact with the stream of low-level
instructions in Angular’s infrastructure, and we can even conveniently pause the stream, while we wait for
something to happen, simply by returning a promise that hasn’t resolved yet. This allows us to: do validation, or
checking that a user session is still open... whatever... before we proceed. By composing and inserting a single
promise object, in the right state, you get that much control, right at the heart of Angular’s operations.
Bonus Detail:
terminate an $http request...
if a promise resolves

(Using the promise API for
mid-stream interventions, not
just outputs...)

Thursday, January 16, 14

Bonus detail: check out the ‘timeout’ property of an $http request’s config object. It shows us yet another model
for the use of promises, where instead of something starting when a promise resolves, we can terminate
something when a promise resolves. Maybe it’s a parallel $http request, and we want to stop whenever one or the
other returns. Or maybe it’s simply a promise indicating an option that was set somewhere. Either way, Angular
knows what to do with it, because a promise is our universal API for all kinds of uncertainty that we want to
conveniently make decisions about.
Best Practices
Use SOA: goes with promises like
peanut butter with chocolate.
Think of promises as the beginning of
a lifecycle or flow or stream, not
just a one-stop ride to a callback.
Decompose handler functions, as
promises make it easy to chain them.

Thursday, January 16, 14
And lest you *still*
thought Promises
weren’t really
mainstream...

Thursday, January 16, 14
Thursday, January 16, 14

• Previously, promises had been a library feature. Now, native promises in the browser are not only part of the
ECMAscript 6 spec, they’re in release, in Chrome 32, as of this very week. Syntax is a little different than the
Promises/A+ spec, but I think in a good way.
• This means that, even though other browsers are going to lag, we can unify around an API for Promises, and
unify around Promises as our key API for uncertainty, and you can invest in learning them knowing that they're not
going anywhere.
• And Not only are they not going anywhere, you're going to HAVE to use them, even outside Angular. New async
DOM APIs will return promises! They'll be unavoidable. Angular ... AND YOU... just got there ahead of the curve.
Thank You!
about.me/XML

Thursday, January 16, 14

More Related Content

Similar to I'm Postal for Promises in Angular

Defensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsDefensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsRuben Tan
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptjnewmanux
 
Beyond the Callback: Yield Control with Javascript Generators
Beyond the Callback: Yield Control with Javascript GeneratorsBeyond the Callback: Yield Control with Javascript Generators
Beyond the Callback: Yield Control with Javascript GeneratorsDarren Cruse
 
Work Queues
Work QueuesWork Queues
Work Queuesciconf
 
Experiments in Reasoning
Experiments in ReasoningExperiments in Reasoning
Experiments in ReasoningAslam Khan
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Codemotion
 
Gearman and CodeIgniter
Gearman and CodeIgniterGearman and CodeIgniter
Gearman and CodeIgniterErik Giberti
 
Quality and reliability: more types of testing
Quality and reliability: more types of testingQuality and reliability: more types of testing
Quality and reliability: more types of testingThe Software House
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScriptTodd Anglin
 
The biggest lies about react hooks
The biggest lies about react hooksThe biggest lies about react hooks
The biggest lies about react hooksMarios Fakiolas
 
Promises, The Tao of Angular
Promises, The Tao of AngularPromises, The Tao of Angular
Promises, The Tao of Angularvmlf
 
Operationalizing Clojure Confidently
Operationalizing Clojure ConfidentlyOperationalizing Clojure Confidently
Operationalizing Clojure ConfidentlyPrasanna Gautam
 
CPAP.com Introduction To Coding: Part 2
CPAP.com Introduction To Coding: Part 2CPAP.com Introduction To Coding: Part 2
CPAP.com Introduction To Coding: Part 2johnnygoodman
 
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018Adam Hill
 

Similar to I'm Postal for Promises in Angular (20)

Defensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsDefensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.js
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Beyond the Callback: Yield Control with Javascript Generators
Beyond the Callback: Yield Control with Javascript GeneratorsBeyond the Callback: Yield Control with Javascript Generators
Beyond the Callback: Yield Control with Javascript Generators
 
Work Queues
Work QueuesWork Queues
Work Queues
 
FNC2751.pdf
FNC2751.pdfFNC2751.pdf
FNC2751.pdf
 
Experiments in Reasoning
Experiments in ReasoningExperiments in Reasoning
Experiments in Reasoning
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
Gearman and CodeIgniter
Gearman and CodeIgniterGearman and CodeIgniter
Gearman and CodeIgniter
 
Quality and reliability: more types of testing
Quality and reliability: more types of testingQuality and reliability: more types of testing
Quality and reliability: more types of testing
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScript
 
The evolution of asynchronous JavaScript
The evolution of asynchronous JavaScriptThe evolution of asynchronous JavaScript
The evolution of asynchronous JavaScript
 
The biggest lies about react hooks
The biggest lies about react hooksThe biggest lies about react hooks
The biggest lies about react hooks
 
Goodparts
GoodpartsGoodparts
Goodparts
 
Promises, The Tao of Angular
Promises, The Tao of AngularPromises, The Tao of Angular
Promises, The Tao of Angular
 
Java Class Design
Java Class DesignJava Class Design
Java Class Design
 
Operationalizing Clojure Confidently
Operationalizing Clojure ConfidentlyOperationalizing Clojure Confidently
Operationalizing Clojure Confidently
 
CPAP.com Introduction To Coding: Part 2
CPAP.com Introduction To Coding: Part 2CPAP.com Introduction To Coding: Part 2
CPAP.com Introduction To Coding: Part 2
 
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018
Oops Youve Got A Mobile Enterprise App – DevFestWeekend 2018
 

Recently uploaded

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 

Recently uploaded (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 

I'm Postal for Promises in Angular

  • 1. I’m POSTAL For PROMISES @ 2014 by: Christian Lilley about.me/xml Thursday, January 16, 14 @xmlilley
  • 2. Intro to Promises on my blog: christianlilley.com Thursday, January 16, 14 We're going to move really fast today, but if you want to go in depth, I’ve got some training slides on my blog. • If you're at ng-conf, chances are, you've at least SEEN promises. They're those weird things you have to extract your data from when they come out of the $http service, right? So, why do they exist?
  • 3. UNCERTAINTY ASYNC Thursday, January 16, 14 • If you've heard of them, you've probably heard that they're about async. Which is true. But that significantly understates their usefulness. Really, they’re designed in a way that lets them be about the bigger, more general idea of uncertainty. About being able to crystallize uncertainty about time, space, user-based uncertainty or almost anything, into a nice neat package, put a bow on it, and give it a super-useful API that provides us with a gorgeous interaction pattern, that allows you to reason about and make DECISIONS about uncertainty throughout your application.
  • 4. BRAINS!!!! Thursday, January 16, 14 • and they're about helping you make the most of your brain when dealing with that uncertainty. Promises make engineer brains work better. Zombie approved.
  • 5. Thursday, January 16, 14 But even though promises ARE about way more than just async, the truth is its what justifies their existence, so let’s talk async. In the beginning was the Word, and the Word was Callback, and the Callback was...
  • 7. Callbacks: Strengths They make Non-Blocking I/O possible. You know how to use them. </strengths> Thursday, January 16, 14 Look, callbacks do the job: they make non-blocking I/O possible, and everybody knows how to use them. But...
  • 8. Callbacks/CPS NOW, NOW, NOW, NOW, NOW, NOW, NOW No API for further interaction No API for crossing contexts Doesn’t Scale: works fine for 1, horrible for more Monolithic Handlers that break your Thursday, January 16, 14 ... they don't scale. They lead us towards huge, monolithic handler functions that try to do everything all at once, and an attitude towards async that it's something you want to do as little of as possible and get it out of the way.
  • 9. step1(value1,  function  (output)  {        step2(output1,  function(output2)  {                step3(output2,  function(output3)  {                        step4(output3,  function(output4)  {                                //  Do  something  with  value4,                                      quick,  before  it                                                                disappears!!!                        });                });        }); }); Thursday, January 16, 14 When you start trying to stack a complex operation with callbacks, things get ugly, and nested, and complex, and unreadable really quickly. We haven’t even put anything into these handler functions yet, and they’re already a mess. See this shape forming here on the left? You know what this shape is called?
  • 10. PYRAMID OF DOOOM!!!! Thursday, January 16, 14 In the PYRAMID of DoOOOOM, we need to do everything RIGHT NOW, because in a second, it's going to be gone. Forget about coming back and picking up later where you left off. And forget about that code being intuitive and readable and clear and maintainable.
  • 11. var  step1Started  =  true; step1(value1,  callback1); var  step1State  =  false; function  callback1(data)  {    step1State  =  true;    step1Data  =  data;    doSomethingWithStep1Data(); } .... later .... if (step1State && step1Data) { doSomethingElseWithStep1(); } Thursday, January 16, 14 •And if you do invade the PYRAMID of DoOOOOM, and try to implement something that does let you leave off in the middle of the pyramid and come back later, you’re going to start building boilerplate like this, caching state variables and outputs, and adding either timers or events to trigger downstream actions. •It works, but good luck with interop with other modules you didn't write, and good luck passing sequenced instructions back and forth between scopes that don't all exist yet, and hence can't listen for events.
  • 12. step1(value1,  callback1); step2(value2,  callback2); var  step1State  =  false; function  callback1(data)  {    step1State  =  true;    step1Data  =  data;    doSomethingWithStep1Data(); } .... timer... later .... if (step1State && step1Data) { doSomethingElseWithStep1(); } var  step2State  =  false; function  callback2(data)  {    step2State  =  true;    step2Data  =  data;    doSomethingWithStep2Data(); } .... timer... later .... if (step2State && step2Data) { doSomethingElseWithStep2(); } step3(value3,  callback3); step4(value4,  callback4); var  step3State  =  false; function  callback3(data)  {    step3State  =  true;    step3Data  =  data;    doSomethingWithStep3Data(); } .... timer ... later .... if (step3State && step3Data) { doSomethingElseWithStep3(); } var  step4State  =  false; function  callback4(data)  {    step4State  =  true;    step4Data  =  data;    doSomethingWithStep4Data(); } .... timer ... later .... if (step4State && step4Data) { doSomethingElseWithStep4(); } Thursday, January 16, 14 And if you want try that with all four of the tasks from that PYRAMID of DoOOOOM, you get this. Mind you, all this junk doesn’t even include any error or success handlers yet. This is JUST what you need to have to be able to talk reasonably about whether these four async functions have fired yet, whether they’ve returned yet, and whether you can do anything useful with their data yet. And NONE of this code is making your application do anything yet. It’s all just a bunch of imperative-style housekeeping that’s hard enough to keep track of and maintain, and even harder to reason about and extend.
  • 14. Thursday, January 16, 14 Let's be clear: promises are not a technical innovation in the javascript execution engine. They don't make anything happen more quickly. They don't execute async operations with different native code. Promises are all about the brains of programmers, the same reason we do automated testing & TDD, talk about principles like 'single responsibility' and 'least surprise'. The promise pattern is about making engineers more efficient, enabling them to actually reason about async sensibly. It allows you to look at async stuff and uncertain stuff, visualize it, and write efficient code AS IF it were predictable, consecutive synchronous operations. And to link those operations together in virtuous cycles or flows.
  • 15. And again, what promises are not: Thursday, January 16, 14 • So, if all that’s true, the naiive understanding of promises needs to go out the door:
  • 16. action(target, callback, error) !== action(target).then( callback, error) Thursday, January 16, 14 Promises are NOT simply a syntax replacement for callbacks. There wouldn't be any point in Promises if that was all there was to it.
  • 17. Promises are just a “replacement for callbacks”... ...if internal combustion was just a “replacement for horses.” Thursday, January 16, 14 Used right, Promises are a qualitative change, a fundamental shift in how we compose and plan for uncertainty and sequencing. So how about an example.
  • 18. IMPERATIVE -------> DECLARATIVE Thursday, January 16, 14 How about if, instead of all that boilerplate I just showed you, what if you could just DECLARE what you want to have happen? That you want a bunch of uncertain things to happen in a certain sequence, based on some other uncertain things?
  • 19. step1. then(step2). then(step3). then(step4) Thursday, January 16, 14 How about that? Welcome to declarative async and uncertainty with promises.
  • 20. step1(value1,  callback1); step2(value2,  callback2); var  step1State  =  false; function  callback1(data)  {    step1State  =  true;    step1Data  =  data;    doSomethingWithStep1Data(); } .... timer... later .... if (step1State && step1Data) { doSomethingElseWithStep1(); } var  step2State  =  false; function  callback2(data)  {    step2State  =  true;    step2Data  =  data;    doSomethingWithStep2Data(); } .... timer... later .... if (step2State && step2Data) { doSomethingElseWithStep2(); } step3(value3,  callback3); step4(value4,  callback4); var  step3State  =  false; function  callback3(data)  {    step3State  =  true;    step3Data  =  data;    doSomethingWithStep3Data(); } .... timer ... later .... if (step3State && step3Data) { doSomethingElseWithStep3(); } var  step4State  =  false; function  callback4(data)  {    step4State  =  true;    step4Data  =  data;    doSomethingWithStep4Data(); } .... timer ... later .... if (step4State && step4Data) { doSomethingElseWithStep4(); } Thursday, January 16, 14 Instead of you writing all this boilerplate just to sequence 4 async operations across your application, and be able to come back and interact with them later...
  • 21. step1. then(step2). then(step3). then(step4) Thursday, January 16, 14 ... all you need is this. This is how the promise pattern sequences things. It knows when it’s allowed to move forward between steps, and keeps everything in order.
  • 23. as1 = step1(); as2 = as1.then(step2); as3 = as2.then(step3); as4 = as3.then(step4); Thursday, January 16, 14 And we can decompose that chain of operations incredibly easily, just by storing a reference to the promises for each stage of that sequence. The promises are the variables on the left. These actions will still fire in the same order as the previous example, but now we can start additional actions, later, whenever and wherever we want, from any point in the middle of the sequence, using the data that comes out of those operations.
  • 24. $HTTP Thursday, January 16, 14 It’s like having DVR, for your async operations. And we can even pass these references into other contexts of the application, without those contexts needing to know anything at all about the process that generated the promise.
  • 25. And if you need parallelism... Thursday, January 16, 14 What if you want to have three of them run in parallel instead of in sequence, and have the fourth one kick in only when all three are done?
  • 26. as4 = $Q.all([as1, as2, as3]) .then(step4) Thursday, January 16, 14 Either, you write all the imperative boilerplate and state variables and other junk we saw before, THEN set a timer to check every few ms to see if they’re all done yet, or use events if you’re lucky... all that OR you do this one line that replaces all of that. That’s composition with promises. That’s the pattern they allow you to work with. So, if that’s the overall pattern, how should we understand the component promise objects themselves?
  • 27. So, in a nutshell, a promise object itself is... Thursday, January 16, 14 So... I promised a certain metaphor in my talk title, even though we don’t have time for all the details here. But at root, understand that a promise is basically just a mailbox.
  • 28. Thursday, January 16, 14 It’s a special, standardized repository where you can stash the data that outputs from an operation, it has a property representing the completion and success state of the operation, and it has utilities for leveraging that knowledge into further operations. And all your functions can have a key to this mailbox, so they know what’s going on. You can even pick this mailbox up and carry it around with you by reference into different contexts of your app, providing your components with all the benefits of async, without needing to understand implementation.
  • 29. If the Promise is the mailbox, then the Deferred: Is the Postman. Thursday, January 16, 14 Then, there’s this thing called the deferred. Lots of folks get Promises but have trouble with the Deferred object. But it’s really straightforward once you think of the promise as a mailbox. The deferred is simply the postman.
  • 30. No, not that one, thank God... Thursday, January 16, 14 No, not THAT endless tribute to Kevin Costner’s vanity, thank god.
  • 31. If the Promise is the mailbox, then the Deferred: Is the Postman. The Postman is the only one who’s allowed to: Assign you a new mailbox. (ie. create a promise) Put new packages into the mailbox. (resolve the promise) Raise the little flag on the side. (set state of the promise) Thursday, January 16, 14 Just like with actual postal workers the postman is the only one who’s allowed to: Assign you a new P.O. Box, put new packages into the mailbox, and, inverting the real life example, let’s pretend the little flag on the side of the mailbox is used to show the box has incoming mail, not outgoing mail. With the deferred, you’re the postman, and you can create and administer the mailbox. Without the deferred, you’re a customer, a promise-consumer.
  • 32. But it’s the pattern that matters most... Thursday, January 16, 14 That’s the main idea. But the pattern of use is more significant than the individual promise objects themselves. Alone, they’re just syntactic sugar.
  • 33. DECLARATIVE, NOT IMPERATIVE. A UNIVERSAL API for uncertainty about time & place. An abstraction for any operation that has happened or will happen. A proxy for a remote object, which allows you to abstract away all the complexity of going and getting it. A zero-boilerplate API for interacting with the state, data, timing & sequence of complex operations. Thursday, January 16, 14 Together, they can change your whole approach to composition, and they can sure as hell reduce the amount of code you write.
  • 34. NOT JUST FOR ASYNC Thursday, January 16, 14 Now, remember, PROMISES ARE NOT JUST FOR ASYNC.
  • 35. userRegistered.then() tutorialComplete.then() purchaseSuccessful.then() profileLocated.then() etc... Thursday, January 16, 14 Time and place uncertainty are certainly the conventional context for promises. But there are other kinds, especially user-related uncertainty. A given AJAX request is actually semi-predictable, within a range. Users, though, are totally unpredictable. You have no idea when - or if - your user will get around to doing certain things, or in what order. Take advantage of promises as a way to encapsulate and abstract this kind of sequencing uncertainty as well, even though it’s not execution engine asynchronousness in the way we mean that term. But using promises, you can build custom async interfaces around user uncertainty.
  • 36. Thursday, January 16, 14 Which brings us to Angular. Angular is an example of what happens when you start thinking in promises, structurally. When you bake them right into the fabric of the application and use them as a way to model process flows and make sure that the right things happen in the right place at the right time, so the different parts of your application can hand-off those flows seamlessly, and customize them. If you think that Misko and Vojta and Igor and Brian and Brad and all the other cats on the angular team are pretty smart, if you're HERE, in other words, then follow their example and get way into promises.
  • 37. 1. Consume promises returned by essential built-in Services. $http $timeout $interval Thursday, January 16, 14 Here’s sort-of an 8-step program to using promises in Angular. Step 1: When you get started with promises, you’ll just consume them, from built-in services that return promises. $http.... and very notably $timeout and $interval. Angular has gone to the trouble to make all of the most fundamental async functions into promise generators, so that Promises can be the seamless common API for all async.
  • 38. var promise= $http.get(‘URL’) promise.then(doSomething); promise.then(doThing2); promise.then(doThing∞); Thursday, January 16, 14 It’s as simple as this: if $http returns a promise, all you have to do is store a reference to that promise. Forever after, for as long as you hold that reference, you can run other operations against it.
  • 39. 2. $resource calls now return promises (in 1.2), & $resource objects *have* one. (Aren’t one. Have one.) Thursday, January 16, 14 Step 2, when you’re ready to get a little tricky, try $resource. (The implementation of $resource has shifted quite a bit in the past, but here’s the 1.2 skinny:) $resource works a little differently than $http, but is nonetheless promise-style processing, via a useful, but perhaps confusing, pattern: $http.get() returns a simple *promise*. But calling the initial .get() method on a $resource type that you’ve defined, returns a... *resource object*, which itself *has* a promise. It Isn't one. But it has one, as a property.
  • 40. var bob = resourceType.get({params}) // returns... Resource {$promise: Object, $resolved: true, $get: function, $save: function, $query: function…} // after that... bob.$promise.then(doStuff) Thursday, January 16, 14 * To chain from that $resource with .then(), just use resourceObject.$promise • Note that the reference is circular. So, if you unwrap a $resource's $promise object, what you get back is the original $resource. Which, of course, still has a $promise. Which you can unwrap. So, the $resource has a $promise which has a $resource which has a $promise...
  • 41. credit: substack/stream-handbook Thursday, January 16, 14 Truly, it’s turtles all the way down. Complicating things further, the other instance methods on a $resources, like $save(), they don’t modify that original promise, instead they return a new bare $promise for the state of the operation, rather than the $resource itself.
  • 42. 3. $route:resolve (Integrating the promise architecture so cleanly that controllers can be fully ignorant of it.) Thursday, January 16, 14 Step 3 is such a big, worthwhile feature that one of the release candidates for the version of Angular it debuted in was named 'promise-resolution'.
  • 43. $routeProvider .when('/dashboard', { templateUrl: 'URL', controller: 'Ctrl', resolve: {myData: ['myService', function(myService) {return myService.get('URL', {params}).$promise }] } Thursday, January 16, 14 Using the :resolve property in the route, you get several huge benefits that you just don’t want to be operating without. 1. the route won’t change until your data has been obtained, and you have everything you need to render the view. No flicker, nothing looks broken. 2. Your controller gets to be totally, completely ignorant of implementation. It doesn’t need to know what a promise is. It doesn’t need to know how to unwrap it, or check the success of the operation. $routeProvider does all of that for you. All the controller gets is a data object, injected at creation time, so it gets to be totally implementation independent.
  • 44. angular.module('myApp') .controller('Ctrl', function(myData) { // do stuff with myData $scope.myData = myData; }) Thursday, January 16, 14 And so then, in the controller, all you have to do is inject the name of the property, and you can do whatever you want with it, like bind it to the $scope.
  • 45. 4. Note: Automatic unwrapping in views: GONE in 1.2 (Too much magic.) Thursday, January 16, 14 Step 4 is just: be aware of a big recent change in Angular 1.2. For a little while there, we could place a promise object on the $scope, and angular would automagically extract the value from it and inject *that* into the view. Yadda yadda yadda, reading the repo, it seems it was just too much magic for people. It made consumers of promises less aware of how they worked and how to use them. It was also slow. So, that feature, which you might see in old documentation on the web, is gone now.
  • 46. Alternatives: Either inject your promises via :resolve, so they’re autounwrapped, or... promise.then(function(value) {$scope.value = value}) Thursday, January 16, 14 Your Alternatives are clear and easy: Either inject promises with the :resolve property if you like magical unwrapping, or just unwrap ‘em yourself.
  • 47. 5. Create your own promises with $Q. (Just like Q.js, only smaller.) Thursday, January 16, 14 Step 5, start creating your own promises with $Q. Check out my detailed slides for more on how to do that.
  • 48. 6. Third-party libraries like angular-ui-bootstrap are built on promises, too. (Great example of workflow: ng-modal.) Thursday, January 16, 14 Step 6: Start noticing how many Third-Party Implementations, like UI-Bootstrap Modal also take advantage of promise flows.
  • 49. $scope.modalOpen = function () { var modalConfigs = { templateUrl: ..., controller: ..., scope: $scope, resolve: { specialData: function () {return $http.get(‘/somedata’);} } } var modalInstance = $modal.open(modalConfigs); modalInstance.result.then(handlerFunc); }; // Inside the modalInstance: result.resolve(); Thursday, January 16, 14 When you define a modal instance, which carries a promise, you immediately define a handler, with modalInstance.result.then(). Before we’ve even had time to do anything with that modal, we’ve already created a handler for whatever we’re going to eventually return from the modal dialog as the result object. We don’t know when or if there will be a return. But we’re ready for it, we can reason about it. And we can easily hand off to some other consumer as well. ALSO: UI-Modal uses its own :resolve property, just like the Angular router does, to ensure that the view won’t be rendered until the data is ready.
  • 50. 7. Wrap a promise in an Angular Service, and you have a *Lazy Promise*. (With lazy promises, time is now fully irrelevant. Point and shoot.) Thursday, January 16, 14 Step 7: promises that you can reference without needing to care if they even exist yet, let alone if they’ve resolved. Normally, you need to know that a promise has been instantiated before you start interacting with it. But because Angular services are instantiated lazily, as needed, and persist throughout application lifecycle, a Promise wrapped in a service can be referenced at any time, from any location, provided you inject the service. The caller of the promise need not know or care anything about the implementation.
  • 51. function getDivision(divisionName) { if (!divisionObjects[divisionName]) { divisionObjects[divisionName] = $http.get(baseUrl + divisionName) .error(function(data, status) { console.error('getDivision failed, error:' + status) }); } else { return divisionObjects[divisionName]; } } Thursday, January 16, 14 • Outside of Angular (or if you want multiple promises in one service) you can do the same thing, using a simple getter function that will return an existing promise if available, or create a new one if not.
  • 52. 8. Interceptors (and the rest of the $http lifecycle) (Great for loaders, other inline transformations.) Thursday, January 16, 14 Step 8: is Master-level! HTTP interceptors are these awesome things that allow you to mess around with every single AJAX operation that goes in or out of your application, all from a single location. And they’re promised based... in BOTH DIRECTIONS, in and out, request and response. Promises, again, aren't just something for async output. They’re part of the modeling of the $http cycle from the very beginning, and you can thus chain even before an async operation kicks off, perhaps executing another async operation before the main one is even allowed to start.
  • 53. $httpProvider.interceptors.push(function($q, $rootScope) { return { 'request': function(config) { $rootScope.$broadcast('asyncLoadStart'); return config || $q.when(config); }, 'requestError': function(rejection) { $rootScope.$broadcast('asyncLoadEnd'); return $q.reject(rejection); }, 'response': function(response) { $rootScope.$broadcast('asyncLoadEnd'); return response || $q.when(response); }, 'responseError': function(rejection) { $rootScope.$broadcast('asyncLoadEnd'); return $q.reject(rejection); } }; }) Thursday, January 16, 14 This example is stripped bare and over-simplified, just so it fits on-screen. It shows a way to trigger an automatic, universal loader screen for your app. With promises, we’re able to interact with the stream of low-level instructions in Angular’s infrastructure, and we can even conveniently pause the stream, while we wait for something to happen, simply by returning a promise that hasn’t resolved yet. This allows us to: do validation, or checking that a user session is still open... whatever... before we proceed. By composing and inserting a single promise object, in the right state, you get that much control, right at the heart of Angular’s operations.
  • 54. Bonus Detail: terminate an $http request... if a promise resolves (Using the promise API for mid-stream interventions, not just outputs...) Thursday, January 16, 14 Bonus detail: check out the ‘timeout’ property of an $http request’s config object. It shows us yet another model for the use of promises, where instead of something starting when a promise resolves, we can terminate something when a promise resolves. Maybe it’s a parallel $http request, and we want to stop whenever one or the other returns. Or maybe it’s simply a promise indicating an option that was set somewhere. Either way, Angular knows what to do with it, because a promise is our universal API for all kinds of uncertainty that we want to conveniently make decisions about.
  • 55. Best Practices Use SOA: goes with promises like peanut butter with chocolate. Think of promises as the beginning of a lifecycle or flow or stream, not just a one-stop ride to a callback. Decompose handler functions, as promises make it easy to chain them. Thursday, January 16, 14
  • 56. And lest you *still* thought Promises weren’t really mainstream... Thursday, January 16, 14
  • 57. Thursday, January 16, 14 • Previously, promises had been a library feature. Now, native promises in the browser are not only part of the ECMAscript 6 spec, they’re in release, in Chrome 32, as of this very week. Syntax is a little different than the Promises/A+ spec, but I think in a good way. • This means that, even though other browsers are going to lag, we can unify around an API for Promises, and unify around Promises as our key API for uncertainty, and you can invest in learning them knowing that they're not going anywhere. • And Not only are they not going anywhere, you're going to HAVE to use them, even outside Angular. New async DOM APIs will return promises! They'll be unavoidable. Angular ... AND YOU... just got there ahead of the curve.