.then
JAVASCRIPT PROMISE
A Good JavaScript Abstraction Pattern
@josephj6802
WHY
Render multiple dropdowns

with non-duplicate AJAX calls
Need AJAX call?
Any same URL
is processing?
Already has

cached data?
All selected values
are matched …
The reason I decided to investigate Promise…
ASYNC & CALLBACK
Handle result when it’s done in the future
Asynchronous Code
Everywhere in JavaScript
setTimeout(function () {!
// do something !
}, 1000);
require(['lodash', 'jquery'], !
function (_, $) {!
// do something with lodash and jQuery!
}!
);
$('form').on('submit', function (e) {!
// do something when user submit form!
});!
!
$('img').on('load', function (e) {!
// do something when img loaded!
});!
!
$('img').on('error', function (e) {!
// do something when img fails loading!
});
$.ajax('/terms.json', function () {!
// do something after api data !
// being loaded!
})
Delay
RequireJS
AJAX
DOM Events
fs.readFile('foo.txt', function () {!
// do something after foo.txt !
// being loaded!
})
Node.js
Asynchronous Code
Everywhere is Callback
setTimeout(function () {!
// do something !
}, 1000);
require(['lodash', 'jquery'], !
function (_, $) {!
// do something with lodash and jQuery!
}!
);
$('form').on('submit', function () {!
// do something when user submit form!
});!
!
$('img').on('load', function () {!
// do something when img loaded!
});!
!
$('img').on('error', function () {!
// do something when img fails loading!
});
$.ajax('/terms.json', function () {!
// do something after api data !
// being loaded!
})
Delay
RequireJS
AJAX
DOM Events
fs.readFile('foo.txt', function () {!
// do something after foo.txt !
// being loaded!
})
Node.js
Asynchronous Code
Everywhere is Callback
setTimeout(function () {!
// do something !
}, 1000);
require(['lodash', 'jquery'], !
function (_, $) {!
// do something with lodash and jQuery!
}!
);
$('form').on('submit', function () {!
// do something when user submit form!
});!
!
$('img').on('load', function () {!
// do something when img loaded!
});!
!
$('img').on('error', function () {!
// do something when img fails loading!
});
$.ajax('/terms.json', function () {!
// do something after api data !
// being loaded!
})
Delay
RequireJS
AJAX
DOM Events
fs.readFile('foo.txt', function () {!
// do something after foo.txt !
// being loaded!
})
Node.js
Nothing wrong with Callback
Use it when your scenario is simple
Sequencial Requests
function GitHubber() {}!
!
GitHubber.prototype.getUserRepos = function (name, callback) {!
!
// Authorisation pass?!
var url = '/api/authorize';

makeRequest(url, function (data, success) {!
// (Omit) Callback if it fails… !
// Get user ID by name!
url = '/api/getUserInfo/' + name + '?token=' + data.token;!
makeRequest(url, function (data, success) {!
// (Omit) Callback if it fails… !
// Get user's repo by user ID!
url = '/api/getUserRepos?token=…&uid=' + data.uid;!
makeRequest(url, function (data, success) {!
// (Omit) Callback if it fails… !
// Finally success

callback(data, true);

});!
});!
});!
};
API Authorisation
Get User ID
Get User Repos
Token
Token + User ID
Callback Hell
GitHubber#getUserRepos
Question: How will you refactor it?
function GitHubber(name) {!
this.name = name;!
this.token = null;!
this.id = null;!
this.repos = [];!
this.steps = ['_authorise', '_getUserInfo', '_getUserRepos'];!
}!
!
var proto = {!
_authorise: function () {!
var url = '/api/authorise';!
makeRequest(url, function (data, success) {!
this.token = data.token;!
this.emit('success', [‘_authorise']);!
});!
},!
_getUserInfo: function () {!
var url = '/api/getUserInfo/' + this.name + 

'?token=' + data.token;!
makeRequest(url, function (data, success) {!
this.id = data.id;!
this.emit('success', [‘_getUserInfo']);!
});!
},!
_getUserRepos: function () {!
var url = '/api/getRepos/?uid=' + this.id + !
'?token=' + data.token;!
makeRequest(url, function (data, success) {!
this.repos = data.repos;!
this.emit('success', [‘_getUserRepos', this.repos]);!
});!
},!
getUserRepos: function (callback) {!
var that = this;!
that.on('success', function (e, method) {!
var offset = that.steps.indexOf(method);!
if (offset !== that.steps.length - 1) { // Other steps!
that[that.steps[offset + 1]];!
} else { // _getUserRepos!
callback(that.repos); !
}!
});!
that[that.steps[0]]();!
}!
};
My Solution
Before understanding Promise
• Break callbacks into
methods with semantic
naming
• Exchange data with
instance variables
• Make use of custom events
I am a big fan of Custom Events
Wolfy87/EventEmitter
function GitHubber(name) {!
this.name = name;!
this.token = null;!
this.id = null;!
this.repos = [];!
this.steps = ['_authorise', '_getUserInfo', '_getUserRepos'];!
}!
!
var proto = {!
_authorise: function () {!
var url = '/api/authorise';!
makeRequest(url, function (data, success) {!
this.token = data.token;!
this.emit('success', [‘_authorise']);!
});!
},!
_getUserInfo: function () {!
var url = '/api/getUserInfo/' + this.name + 

'?token=' + data.token;!
makeRequest(url, function (data, success) {!
this.id = data.id;!
this.emit('success', [‘_getUserInfo']);!
});!
},!
_getUserRepos: function () {!
var url = '/api/getRepos/?uid=' + this.id + !
'?token=' + data.token;!
makeRequest(url, function (data, success) {!
this.repos = data.repos;!
this.emit('success', [‘_getUserRepos', this.repos]);!
});!
},!
getUserRepos: function (callback) {!
var that = this;!
that.on('success', function (e, method) {!
var offset = that.steps.indexOf(method);!
if (offset !== that.steps.length - 1) { // Other steps!
that[that.steps[offset + 1]];!
} else { // _getUserRepos!
callback(that.repos); !
}!
});!
that[that.steps[0]]();!
}!
};
My Solution
Before understanding Promise
• Break callbacks into
methods with semantic
naming
• Exchange data with
instance variables
• Make use of custom events
I am a big fan of Custom Events
Wolfy87/EventEmitter
Better but still not straightforward
Need read carefully to understand the trick
ex. sequence, error handling, and parallel events
JavaScript Promise
Developer’s Wonderland
PROMISE
• A Programming Pattern
• Specialise on Asynchronous Code
• Better Maintainability
• Easier for Scaling
NOT another JavaScript framework
Create A Promise
.then Returns promise immediately
getUserRepos: function () {
!
!
!
},
“Our workers will do
all tasks for you”
“Keep the ticket for now.
I promise you will get 

a fulfilled or rejected result”
• Pending
• Fulfilled: that.repoDeferred.resolve(data.repos)
• Rejected: that.repoDeferred.reject(‘service unavailable’)
that.repoDeferred = new $.Deferred();
that.asyncTasks()
return that.repoDeferred.promise();
“This task may take a while”
Use Promise
.then
gitHubber.getUserRepos()


!
Chain-able fulfilled callback
Rejected callback
Promise is still callback
• .then(fnFulfilled, fnRejected)
• .done(fnFulfilled)
• .fail(fnRejected)
.then(function (repos) {})
.catch(function (msg) {});
Batch Promise
.then
var deferreds = [
gitHubber.getUserRepos(),
gitHubber.getUserProfile(),
gitHubber.getOrgaizations()
];
!
$.when(deferreds)
.done(fnFulfilled)
.fail(fnRejected);
All succeeds
Execute multiple promises together
One or more fails
Promises Array
1st Refactoring
Not attractive… :(
function GitHubber(name) {!
this.name = name;!
this.repos = [];!
this.deferreds = {};!
}!
!
var proto = {!
_authorise: function () {!
var that = this,!
url = '/api/authorise';!
!
that.deferreds._authorise = $.Deferreds();!
$.ajax(url, function (data) {!
that.deferreds._authorise.resolve(data);!
});!
return that.deferreds._authorise.promise();!
},!
_getUserInfo: function () {!
var that = this,!
url = '/api/getUserInfo/' + this.name + '?token=' + data.token;!
!
that.deferreds._getUserInfo = $.Deferreds();!
$.ajax(url, function (data) {!
that.deferreds._getUserInfo.resolve(data.id);!
});!
return that.deferreds._getUserInfo.promise();!
},!
_getUserRepos: function () {!
var that = this,!
url = '/api/getRepos/?uid=' + this.id + '?token=' + data.token;!
!
that.deferreds._getUserRepos = $.Deferreds();!
$.ajax(url, function (data) {!
that.deferreds._getUserRepos.resolve(data.repos);!
});!
function GitHubber (name) {!
this.name = name;!
this.token = null;!
that.repos = [];!
}!
!
var proto = {!
getUserRepos: function (callback) {!
var that = this,!
deferred = $.Deferred();!
!
if (that.repos.length) {!
deferred.resolve(that.repos);!
return;!
}!
!
$.ajax('/api/authorise')!
.then(function (data) {!
that.token = data.token;!
return $.ajax('/api/getUserInfo/' + that.name +'?token=' + data.token);!
})!
.then(function (data) {!
return $.ajax('/api/getRepos/?uid=' + data.uid + '?token=' + that.token);!
})!
.then(function (data) {!
that.repos = data.repos;!
deferred.resolve(data.repos);!
});!
!
return deferred.promise();!
}!
};
2nd: jQuery Promises
$.ajax
$.when
$.getJSON
$.ajax() is also a promise object!
function GitHubber (name) {!
this.name = name;!
this.token = null;!
that.repos = [];!
}!
!
var proto = {!
getUserRepos: function (callback) {!
var that = this,!
deferred = $.Deferred();!
!
if (that.repos.length) {!
deferred.resolve(that.repos);!
return;!
}!
!
$.ajax('/api/authorise')!
.then(function (data) {!
that.token = data.token;!
return $.ajax('/api/getUserInfo/' + that.name +'?token=' + data.token);!
})!
.then(function (data) {!
return $.ajax('/api/getRepos/?uid=' + data.uid + '?token=' + that.token);!
})!
.then(function (data) {!
that.repos = data.repos;!
deferred.resolve(data.repos);!
});!
!
return deferred.promise();!
}!
};
2nd: jQuery Promises
$.ajax
$.when
$.getJSON
$.ajax() is also a promise object!
You can reduce huge amount of code
by chaining & wrapping promise object properly
Promise v.s. Callback
Why Promise?
var promise = $.ajax(url);!
promise.done(callback);
$.ajax(url, callback)
Promise Callback
• Portability - async task must be fulfilled or rejected in delegated methods.
• Consistency - .resolve(), .reject() , .then(), .done(), .catch(), rejected, fulfilled, pending
• Chaining - .then() makes sequential tasks easier to execute
• Straightforward - .then() makes our code easier to read
“First-class API for asynchronous tasks”
Scalability
UserSession.signIn()
.then(this._promisePurchase(video))
Using JavaScript Promises to Reason About
User Interaction
Abstracted Session Checking, Login Popup, Validation,
Video Purchasing and Watching Video with Promise!
With Promise…
.then
• We defines sequence in a very straightforward
way (.then)
• Built-in error handling API (.fail)
• Batch execute parallel tasks easily (Promise.all)
Solved a lot of async design issues
PROMISE IN THE WILD
Environments and Libraries for Promise
Standard Spec: Promises/A+
Promise in Browsers
All Modern browsers support Promise
except IE 11 and all its earlier versions
Promise & jQuery
jQuery’s Deferreds aren't Promise/A+ compliant. 

Please avoid to use if you want to use Promise extensively.
$.Deferred
$.when
Promise in Node.js
Node.js added native promise
in stable version 0.12
… comes with memory leak
Libraries
For both Browser and Node.js
• Q.js 

A tool for creating and composing asynchronous promises in JavaScript
• RSVP.js

A lightweight library that provides tools for organising asynchronous code
• when.js

A solid, fast Promises/A+ and when() implementation, plus other async goodies.
• bluebird (most popular)

Bluebird is a full featured promise library with unmatched performance.
Libraries
For both Browser and Node.js
• Q.js 

A tool for creating and composing asynchronous promises in JavaScript
• RSVP.js

A lightweight library that provides tools for organising asynchronous code
• when.js

A solid, fast Promises/A+ and when() implementation, plus other async goodies.
• bluebird (most popular)

Bluebird is a full featured promise library with unmatched performance.
Currently you probably need library for polyfills
Use jQuery Deferred with awareness
Q & A
• Promise - A Programming Pattern
• Specialise on Asynchronous Code
• Better Maintainability
• Easier for Scaling
“First-class API for asynchronous tasks”
Thank You!

JavaScript Promise

  • 1.
    .then JAVASCRIPT PROMISE A GoodJavaScript Abstraction Pattern @josephj6802
  • 2.
    WHY Render multiple dropdowns
 withnon-duplicate AJAX calls Need AJAX call? Any same URL is processing? Already has
 cached data? All selected values are matched … The reason I decided to investigate Promise…
  • 3.
    ASYNC & CALLBACK Handleresult when it’s done in the future
  • 4.
    Asynchronous Code Everywhere inJavaScript setTimeout(function () {! // do something ! }, 1000); require(['lodash', 'jquery'], ! function (_, $) {! // do something with lodash and jQuery! }! ); $('form').on('submit', function (e) {! // do something when user submit form! });! ! $('img').on('load', function (e) {! // do something when img loaded! });! ! $('img').on('error', function (e) {! // do something when img fails loading! }); $.ajax('/terms.json', function () {! // do something after api data ! // being loaded! }) Delay RequireJS AJAX DOM Events fs.readFile('foo.txt', function () {! // do something after foo.txt ! // being loaded! }) Node.js
  • 5.
    Asynchronous Code Everywhere isCallback setTimeout(function () {! // do something ! }, 1000); require(['lodash', 'jquery'], ! function (_, $) {! // do something with lodash and jQuery! }! ); $('form').on('submit', function () {! // do something when user submit form! });! ! $('img').on('load', function () {! // do something when img loaded! });! ! $('img').on('error', function () {! // do something when img fails loading! }); $.ajax('/terms.json', function () {! // do something after api data ! // being loaded! }) Delay RequireJS AJAX DOM Events fs.readFile('foo.txt', function () {! // do something after foo.txt ! // being loaded! }) Node.js
  • 6.
    Asynchronous Code Everywhere isCallback setTimeout(function () {! // do something ! }, 1000); require(['lodash', 'jquery'], ! function (_, $) {! // do something with lodash and jQuery! }! ); $('form').on('submit', function () {! // do something when user submit form! });! ! $('img').on('load', function () {! // do something when img loaded! });! ! $('img').on('error', function () {! // do something when img fails loading! }); $.ajax('/terms.json', function () {! // do something after api data ! // being loaded! }) Delay RequireJS AJAX DOM Events fs.readFile('foo.txt', function () {! // do something after foo.txt ! // being loaded! }) Node.js Nothing wrong with Callback Use it when your scenario is simple
  • 7.
    Sequencial Requests function GitHubber(){}! ! GitHubber.prototype.getUserRepos = function (name, callback) {! ! // Authorisation pass?! var url = '/api/authorize';
 makeRequest(url, function (data, success) {! // (Omit) Callback if it fails… ! // Get user ID by name! url = '/api/getUserInfo/' + name + '?token=' + data.token;! makeRequest(url, function (data, success) {! // (Omit) Callback if it fails… ! // Get user's repo by user ID! url = '/api/getUserRepos?token=…&uid=' + data.uid;! makeRequest(url, function (data, success) {! // (Omit) Callback if it fails… ! // Finally success
 callback(data, true);
 });! });! });! }; API Authorisation Get User ID Get User Repos Token Token + User ID Callback Hell GitHubber#getUserRepos Question: How will you refactor it?
  • 8.
    function GitHubber(name) {! this.name= name;! this.token = null;! this.id = null;! this.repos = [];! this.steps = ['_authorise', '_getUserInfo', '_getUserRepos'];! }! ! var proto = {! _authorise: function () {! var url = '/api/authorise';! makeRequest(url, function (data, success) {! this.token = data.token;! this.emit('success', [‘_authorise']);! });! },! _getUserInfo: function () {! var url = '/api/getUserInfo/' + this.name + 
 '?token=' + data.token;! makeRequest(url, function (data, success) {! this.id = data.id;! this.emit('success', [‘_getUserInfo']);! });! },! _getUserRepos: function () {! var url = '/api/getRepos/?uid=' + this.id + ! '?token=' + data.token;! makeRequest(url, function (data, success) {! this.repos = data.repos;! this.emit('success', [‘_getUserRepos', this.repos]);! });! },! getUserRepos: function (callback) {! var that = this;! that.on('success', function (e, method) {! var offset = that.steps.indexOf(method);! if (offset !== that.steps.length - 1) { // Other steps! that[that.steps[offset + 1]];! } else { // _getUserRepos! callback(that.repos); ! }! });! that[that.steps[0]]();! }! }; My Solution Before understanding Promise • Break callbacks into methods with semantic naming • Exchange data with instance variables • Make use of custom events I am a big fan of Custom Events Wolfy87/EventEmitter
  • 9.
    function GitHubber(name) {! this.name= name;! this.token = null;! this.id = null;! this.repos = [];! this.steps = ['_authorise', '_getUserInfo', '_getUserRepos'];! }! ! var proto = {! _authorise: function () {! var url = '/api/authorise';! makeRequest(url, function (data, success) {! this.token = data.token;! this.emit('success', [‘_authorise']);! });! },! _getUserInfo: function () {! var url = '/api/getUserInfo/' + this.name + 
 '?token=' + data.token;! makeRequest(url, function (data, success) {! this.id = data.id;! this.emit('success', [‘_getUserInfo']);! });! },! _getUserRepos: function () {! var url = '/api/getRepos/?uid=' + this.id + ! '?token=' + data.token;! makeRequest(url, function (data, success) {! this.repos = data.repos;! this.emit('success', [‘_getUserRepos', this.repos]);! });! },! getUserRepos: function (callback) {! var that = this;! that.on('success', function (e, method) {! var offset = that.steps.indexOf(method);! if (offset !== that.steps.length - 1) { // Other steps! that[that.steps[offset + 1]];! } else { // _getUserRepos! callback(that.repos); ! }! });! that[that.steps[0]]();! }! }; My Solution Before understanding Promise • Break callbacks into methods with semantic naming • Exchange data with instance variables • Make use of custom events I am a big fan of Custom Events Wolfy87/EventEmitter Better but still not straightforward Need read carefully to understand the trick ex. sequence, error handling, and parallel events
  • 10.
  • 11.
    PROMISE • A ProgrammingPattern • Specialise on Asynchronous Code • Better Maintainability • Easier for Scaling NOT another JavaScript framework
  • 12.
    Create A Promise .thenReturns promise immediately getUserRepos: function () { ! ! ! }, “Our workers will do all tasks for you” “Keep the ticket for now. I promise you will get 
 a fulfilled or rejected result” • Pending • Fulfilled: that.repoDeferred.resolve(data.repos) • Rejected: that.repoDeferred.reject(‘service unavailable’) that.repoDeferred = new $.Deferred(); that.asyncTasks() return that.repoDeferred.promise(); “This task may take a while”
  • 13.
    Use Promise .then gitHubber.getUserRepos() 
 ! Chain-able fulfilledcallback Rejected callback Promise is still callback • .then(fnFulfilled, fnRejected) • .done(fnFulfilled) • .fail(fnRejected) .then(function (repos) {}) .catch(function (msg) {});
  • 14.
    Batch Promise .then var deferreds= [ gitHubber.getUserRepos(), gitHubber.getUserProfile(), gitHubber.getOrgaizations() ]; ! $.when(deferreds) .done(fnFulfilled) .fail(fnRejected); All succeeds Execute multiple promises together One or more fails Promises Array
  • 15.
    1st Refactoring Not attractive…:( function GitHubber(name) {! this.name = name;! this.repos = [];! this.deferreds = {};! }! ! var proto = {! _authorise: function () {! var that = this,! url = '/api/authorise';! ! that.deferreds._authorise = $.Deferreds();! $.ajax(url, function (data) {! that.deferreds._authorise.resolve(data);! });! return that.deferreds._authorise.promise();! },! _getUserInfo: function () {! var that = this,! url = '/api/getUserInfo/' + this.name + '?token=' + data.token;! ! that.deferreds._getUserInfo = $.Deferreds();! $.ajax(url, function (data) {! that.deferreds._getUserInfo.resolve(data.id);! });! return that.deferreds._getUserInfo.promise();! },! _getUserRepos: function () {! var that = this,! url = '/api/getRepos/?uid=' + this.id + '?token=' + data.token;! ! that.deferreds._getUserRepos = $.Deferreds();! $.ajax(url, function (data) {! that.deferreds._getUserRepos.resolve(data.repos);! });!
  • 16.
    function GitHubber (name){! this.name = name;! this.token = null;! that.repos = [];! }! ! var proto = {! getUserRepos: function (callback) {! var that = this,! deferred = $.Deferred();! ! if (that.repos.length) {! deferred.resolve(that.repos);! return;! }! ! $.ajax('/api/authorise')! .then(function (data) {! that.token = data.token;! return $.ajax('/api/getUserInfo/' + that.name +'?token=' + data.token);! })! .then(function (data) {! return $.ajax('/api/getRepos/?uid=' + data.uid + '?token=' + that.token);! })! .then(function (data) {! that.repos = data.repos;! deferred.resolve(data.repos);! });! ! return deferred.promise();! }! }; 2nd: jQuery Promises $.ajax $.when $.getJSON $.ajax() is also a promise object!
  • 17.
    function GitHubber (name){! this.name = name;! this.token = null;! that.repos = [];! }! ! var proto = {! getUserRepos: function (callback) {! var that = this,! deferred = $.Deferred();! ! if (that.repos.length) {! deferred.resolve(that.repos);! return;! }! ! $.ajax('/api/authorise')! .then(function (data) {! that.token = data.token;! return $.ajax('/api/getUserInfo/' + that.name +'?token=' + data.token);! })! .then(function (data) {! return $.ajax('/api/getRepos/?uid=' + data.uid + '?token=' + that.token);! })! .then(function (data) {! that.repos = data.repos;! deferred.resolve(data.repos);! });! ! return deferred.promise();! }! }; 2nd: jQuery Promises $.ajax $.when $.getJSON $.ajax() is also a promise object! You can reduce huge amount of code by chaining & wrapping promise object properly
  • 18.
    Promise v.s. Callback WhyPromise? var promise = $.ajax(url);! promise.done(callback); $.ajax(url, callback) Promise Callback • Portability - async task must be fulfilled or rejected in delegated methods. • Consistency - .resolve(), .reject() , .then(), .done(), .catch(), rejected, fulfilled, pending • Chaining - .then() makes sequential tasks easier to execute • Straightforward - .then() makes our code easier to read “First-class API for asynchronous tasks”
  • 19.
    Scalability UserSession.signIn() .then(this._promisePurchase(video)) Using JavaScript Promisesto Reason About User Interaction Abstracted Session Checking, Login Popup, Validation, Video Purchasing and Watching Video with Promise!
  • 20.
    With Promise… .then • Wedefines sequence in a very straightforward way (.then) • Built-in error handling API (.fail) • Batch execute parallel tasks easily (Promise.all) Solved a lot of async design issues
  • 21.
    PROMISE IN THEWILD Environments and Libraries for Promise Standard Spec: Promises/A+
  • 22.
    Promise in Browsers AllModern browsers support Promise except IE 11 and all its earlier versions
  • 23.
    Promise & jQuery jQuery’sDeferreds aren't Promise/A+ compliant. 
 Please avoid to use if you want to use Promise extensively. $.Deferred $.when
  • 24.
    Promise in Node.js Node.jsadded native promise in stable version 0.12 … comes with memory leak
  • 25.
    Libraries For both Browserand Node.js • Q.js 
 A tool for creating and composing asynchronous promises in JavaScript • RSVP.js
 A lightweight library that provides tools for organising asynchronous code • when.js
 A solid, fast Promises/A+ and when() implementation, plus other async goodies. • bluebird (most popular)
 Bluebird is a full featured promise library with unmatched performance.
  • 26.
    Libraries For both Browserand Node.js • Q.js 
 A tool for creating and composing asynchronous promises in JavaScript • RSVP.js
 A lightweight library that provides tools for organising asynchronous code • when.js
 A solid, fast Promises/A+ and when() implementation, plus other async goodies. • bluebird (most popular)
 Bluebird is a full featured promise library with unmatched performance. Currently you probably need library for polyfills Use jQuery Deferred with awareness
  • 27.
    Q & A •Promise - A Programming Pattern • Specialise on Asynchronous Code • Better Maintainability • Easier for Scaling “First-class API for asynchronous tasks”
  • 28.