Share
Embed
Dealing with asynchronous JavaScript: Events, Callbacks & Promises/Deferreds
In real-world applications, we often deal with asynchronous code, for example to retrieve data from various systems. In this session, Lee Boonstra will talk about the various ways on how to deal with asynchronous bit of code. A talk about Events, Callbacks and the new Ext JS 6 Promises.
Lee Boonstra
September 07, 2015
Transcript
52 slides
-
Which value will be alerted? var i = 5;
function calc(num){ setTimeout(function(){ i = i * 0; return i; }, 3000); i = i * 5; } calc(5); alert(i); Answer? A) 5 B) 25 C) 0 -
JavaScript is Single Threaded • Code executes from top to
bottom • Right after each other • 2 bits of code cannot run at the same time -
The Event Loop • Queue of callback functions • JS
engine won’t start processing after the code after the method has been executed -
So, how to deal with async code? • Events •
Callbacks • Promises -
Observer Pattern • Events are a solution to communicate when
async callbacks finish executing. • Objects can publish events that other objects can listen for. • Ext.mixin.Observable -
Types of events • User Events • System Events •
Life Cycle Events button.addListener('tap', function(c) { //do something }); User Event store.on('load', function(store) { //do something }); System Event grid.on('afterrender', function(c) { //do something }); Life Cycle Event -
View ViewController Ext.define(‘MyApp.view.MyViewController’, extend: ‘Ext.app.ViewController’, alias: 'controller.myviewcontroller',
onAfterRender: function(){ //do something… } … .. controller: ‘myviewcontroller’, listeners: { ‘tap’ : ‘onButtonTap’, ‘afterrender':‘onAfterRender’ } MVVM Listeners -
“Events are great for things that can happen multiple times
on the same object. With those events you don't really care about what happened before you attached the listener. But when it comes to asynchronous methods which have on success or on failure behavior, you rather want to use callbacks.” -
Callback • Commonly used in asynchronous operations • When you
call a function, pass in another function as argument -
Example Ext.Ajax.request({ url: 'feed.json',
success: function(response, opts) { //doSomething() }, failure: function(response, opts) { //doSomething() } }); -
Example mystore.sync({ success: function(batch, o){ }, failure: function(batch,
o){ }, callback: function(batch, o){ } }); -
Tip! • Always use a loading spinner before you make
your asynchronous call. • Never forget to clear the spinner, on success and failure. -
Actor MainController user clicks play request selection from grid Grid
SpotifyManager check if artist, track or album execute spotify return record make JsonP request play song / display error -
Example VC //app/view/main/MainController.js onPlay: function(){ var s =
me.getViewModel().get(‘mygrid’).selection; var rec = s.getData(); //spinner Engine.manager.Spotify.execSpotify(rec, doneFnSpotify); } -
Callback horror • Unmaintainable / unreadable code due too many
nested callbacks. • This is where JavaScript promises might become handy! -
Promise • represents a “contract” for a value not securely
known when the promise is created • an object or function with a “then” method whose behavior conforms to this specification. • A Promise can only succeed or fail once. -
Promise states • fulfilled - the action relating to the
promise succeeded • rejected - the action relating to the promise failed • pending - hasn't fulfilled or rejected yet • settled - has fulfilled or rejected -
The Promises A+ Spec This specification details the behavior of
the then method, providing an interoperable base which all Promises/A+ conformant promise implementations can be depended on to provide. https://github.com/promises-aplus/promises-spec Ext JS 6 & Web Application Manager Promises are conform this spec! -
An example of a Promise in JavaScript (ECMAScript 6): var
p = new Promise(function(resolve, reject) { //do something(); if (/* everything turned out fine */) { resolve("OK"); } else { reject(Error("Oh no!")); } }); -
How to use: p.then(function(result) { console.log(result); // "OK"
}, function(err) { console.log(err); // Error: "Oh no!" }); -
example of a callback, later I will rewrite it to
use a promise var done = function(err, jobs){ res.render("myview", { user : req.user, jobs: jobs }); }; getJobs = function(req, done){ Job.findJobsOfUser(req.user._id, function(err, jobs){ if(err) throw err; done(null, jobs); }); } var jobs = getJobs(req, done); This becomes callback horror, when I want to load more things, before rendering the page. -
My solution, with the use of Promises… getJobs(req).then(function(jobs){
if(jobs){ //now if I want to chain this with more calls //i just run the res.render call last (or finally) res.render("profile", { user : req.user, jobs: jobs }); } }, function(error){ throw error; }); -
How to use: function getJobs(req){ var promise
= new Promise(function (resolve, reject) { Job.findJobsOfUser(req.user._id, function (err, jobs) { if (err) reject(err); else resolve(jobs); }); }); return promise; } -
Promises in Ext JS • Ext JS 6 conforms Promises/A
spec • Ext.Ajax is thenable. • Two forms: Ext.Promise() & Ext.Deferred() • Ext.Promise() - ECS6 wrapper • Ext.Deferred() - extra enhancements -
Example Ext.Promise requestUserName: function(){
var s = this.getStore(); return new Ext.Promise(function (resolve, reject) { s.load({ callback: function(records, operation, success) { if(success){ if(records.length > 0){ resolve(records); } else { resolve(false); } } else{ reject(operation); } } }); }); } -
Use Ext.Promise this.requestUserName().then(function(records){ if(records){
//do something } }, function(error){ //throw error }); -
Instance methods • p.then(onFulfilled, onRejected, onProgress) • p.done() • p.cancel(reason)
• p.always(onCompleted) • p.otherwise(onRejected) -
Ext.Ajax built-in Promises Ext.Ajax.request({ url: 'feed.json',
}).then(function (response) { // use response }); //Ext.Ajax extends from Ext.data.request.Base -
Ext.Ajax.request({ url: 'feed.json', }).then(function(response) {
// use response }).always(function() { // clean-‐up logic, regardless the outcome }).otherwise(function(reason){ // handle failure }); -
Promises in Web Application Manager • Invoke API (to invoke
other applications) • Device Camera API • Download Files API • File Collections & Secure Files APIs • Secure LocalStorage API • … -
Actor SETTINGS user clicks username save request username from localstorage
LOCAL STORAGE LASTFM MANAGER return results to the user request lastfm playlist return result if no records exist, add new, else edit return username -
Deferreds • mechanism used to create new Promises with Ext
JS 6 • Promises with additional features -
Ext.Deferred doSomething: function () {
var d = new Ext.Deferred(); //create the Ext.Deferred object mystore.load({ callback: function (records, operation, success) { if (success) { // Use "deferred" to drive the promise: d.resolve(records); } else { // Use "deferred" to drive the promise: d.reject("Error loading data."); } } }); return d.promise; // return the Promise to the caller } -
Async JavaScript Events • Observer Pattern. Users, System and the
LifeCycle can throw events, which are asynchronous. - There is no success or failure. -
Async JavaScript Callbacks • Asynchronous JS. You pass a function
in a function, deal with on success or failure. -
Async JavaScript Promises • The result of a task, which
can be fulfilled or rejected. Promises are chain-able. -
Async JavaScript Ext.Deferred • Like Promises, but can be used
as a base class, to let your methods return promises. • Sencha deferreds give additional extras -
Resources • http://docs.sencha.com/extjs/6.0/6.0.0-classic/#!/api/Ext.Promise • http://docs.sencha.com/extjs/6.0/6.0.0-classic/#!/api/Ext.promise.Promise-method-then • http://docs.sencha.com/extjs/6.0/6.0.0-classic/#!/api/Ext.Deferred • https://github.com/promises-aplus/promises-spec •
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise