Asynchronous JavaScript: Promises

Posted on in Ext JS 6 Uncategorized

JavaScript is single threaded, causing code to execute from top to bottom, so two bits of code cannot run at the same time. For example, you might download a JSON file from an (external) server and you’d have to wait until you retrieve that file. Instead of blocking the thread, there are ways you can streamline this code execution by using asynchronous JavaScript.

You’re probably already familiar with asynchronous JavaScript. Events (observer pattern) and Callbacks are examples of asynchronous code. For example, whenever you make an Ext.Ajax request or a user presses a button, the action is pushed into a queue, which is called the event loop. The JavaScript engine doesn’t start processing the event loop until the code has been executed after an async function (from top to bottom). This means that JavaScript code is not multi-threaded even though it appears to be so.

Event Loop

Callbacks are often used when you have an async operation (for example, loading data from a database) that should notify the caller about its completion. When calling such a function, you can pass it another function as an argument, which confirms that something has happened. Putting callbacks into callbacks is a great solution, and I think that’s one of the powerful features of JavaScript. However, it can be messy when your code requires other asynchronous pieces of code first.

For example, you read your user settings from local storage (that’s a callback!). Based on those settings, you make a request from some external server with a database connection, (that’s callback #2). Before you render that information on the screen, you retrieve something else from the database (that’s callback #3).

These steps are very common when you build a large enterprise app. In your code, there will be a callback function, written in a callback function, that’s in another callback function. You can imagine if these functions are spread over separate files that you’d have a hard time reading this code back a month later.

This is where JavaScript Promises comes into play. It’s a new way of writing your code in a more readable and understandable way. A Promise represents the result of a task, which may or may not have been completed. Like a contract for a value that we might not know when the promise is created. It’s an object or function with a then method. Because of the “then” method, the action can be chained endlessly, and that’s awesome!

A Promise typically has one of these 4 states.

  • fulfilled – when the promise succeeds
  • rejected – when the promise failed
  • pending – ongoing, hasn’t been fulfilled or rejected yet
  • settled – it has been fulfilled or rejected already

JavaScript Promises

Promises is part of ECMAScript 6, which is available in the client of some modern browsers, and also within the latest version of Node.js. The following browsers do not support JavaScript Promises: Explorer 11 and below, Android 4.4 and below, and iOS Safari 7.1 and below.

Ext JS 6 supports Promises and conforms to the Promises A+ spec; both Classic and Modern toolkits are included. You can call the Sencha Promises class, which is a wrapper for the native JavaScript functionality. Legacy browsers will use the fallback provided by Sencha, and modern browsers will use the native functionality.

Here’s an example of a function that returns a Sencha Promise object:

requestUserSettings: function(){
        return new Ext.Promise(function (resolve, reject) {
            //something asynchronous, like loading a store
            Ext.getStore(‘Settings’).load({
                callback: function(records, operation, success) {
                        if(success){
                            if(records.length > 0){
                            //when it’s ok
                                resolve(records);
                            } else {
                            //still ok, but no results
                                resolve(false);
                            }
                        } else{
                        //something bad happened
                            reject(operation);
                        }
                  }
            });
        });
}

The Ext.Promise constructor takes one argument, a callback with two parameters, resolve and reject. When it does something asynchronous within the callback, like retrieving user settings from a local storage store, then it calls “resolve”; if everything worked it passes in the result, otherwise it calls “reject” and passes in what went wrong.

Here’s how you use that Promise:

this.requestUserSettings().then(function(records) {
  //It’s ok. do something with the records
}, function(err) {
  //oh no, something went wrong, display a nice error
});

The “then” takes two arguments, a callback for a success case, and another one for the failure case our website. Both are optional, so you can add a callback for the success or failure case only. You can chain as many then methods as you want to run additional async actions one after another.

Besides the “then()” instance method, there are also ways to terminate a Promise chain (“done()”), cancel pending chains (“cancel()”). Also, there’s a way to attach an onCompleted callback to the chain (“always()”), for example with cleanup logic regardless the outcome. And, you can attach an onRejected callback, if one action within the chain is rejected (“otherwise()”), for example to handle failures.

In addition to Ext.Promise, Sencha will also ship Ext.Deferred, which is a mechanism used to create new Promises within Ext JS 6. The difference between these two constructors is that with a deferred constructor the creator has direct access to “behind the scenes” extras, such as progress updates.

Last but not least, Sencha integrated Promises support into Ext.Ajax.

Ext.Ajax.request() is now an instance of a class derived from Ext.data.request.Base which can be used with a then method. It allows you to write code like this:

Ext.Ajax.request({
    url: 'feed.json',
}).then(function(response) {
    // use response
}).always(function() {
   // clean-up logic, regardless the outcome
}).otherwise(function(reason){
   // handle failure
});

More Resources

There’s a lot more information to explain how you can use JavaScript & Ext JS Promises. Take a look at these resources to learn more!

Connect & play around with BB-8 by Sphero with JavaScript on a Mac

Posted on in JavaScript Robotics

I'm a huge Star Wars fan, and like most of you, i've seen The Force Awakens as well. I immediately felt in love with BB-8. The little white orange droid.
So you can imagine, how happy I was, when I opened my christmas presents, and found the little BB-8 by Sphero droid in a box.

BB-8 by Sphero, is a little toy robot that you can control with apps for Android and iOS, via bluetooth. Actually the sphere is the true robot, BB-8's head is attached to the big sphere, via a magnet, and it has little wheels so it always stays on top, and gives it the Looney Toones Road runner look, while rolling. Cute.

This little droid has the following functionalities; it can roll around (quiet fast,), it can listen to your voice (via the app), it can show colors, it has IMU, 3 axis accelerometer, 3 axis rotation gyro and locator sensors.
The BB-8 uses a Bluetooth Low Energy (LE) interface, also known as "Bluetooth Smart" or "Bluetooth 4.0/4.1". What's really awesome is that Sphero opens up their APIs, so developers like me, can play around with this. And that's great.
There are SDKs for Android, iOS, Windows development, and there's a JavaScript SDK!

Since I'm a JavaScript lover, I thought, let's give it a go, and try this out myself. Here's are the steps that I took, to get it all up and running.

I tried it on a Mac OSX with XCode installed. You will need an editor and Node JS on your machine. With these base requirements, you will need to install the Sphero SDK, and also Noble, a hardware adapter that supports the Bluetooth 4.x+ standard to connect your computer to your BB-8. https://github.com/sandeepmistry/noble
With Noble, you can read out the bluetooth information, which you will later need while writing your code.

To get Noble up and running I had to fix my system paths. I've added the following to my bashprofile, to make sure Noble and XPC-Connection which is what the package uses under the hood, don't run into build errors:

export MYBIN=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin
export PATH=${MYBIN}:${PATH}

Then afterwards, run the following commands to make a connection from your computer:

The UUID is what you'll need. I wrote this simple script, which I run in Node to make a simple connection with my little friend, and read out his information:

It doesn't do anything special yet, other than switching some colors, but this is a great start. My next goal will be to create my own Sencha universal app, to control BB-8 via a web interface. I'll need a Node JS Express back-end for that: Once, I'm done with that I can share this, in another blog post, but here's a start:
https://github.com/savelee/bb8-starwars

For now, take a look into these resources:

My SenchaCon introduction

Posted on in Sencha

On April 7-9 in the heart of Silicon Valley at the Santa Clara Convention Center, Sencha is organising a huge developer conference. It’s going to be three days jam packed with nearly 50 technical sessions led by Sencha engineers, partners and key customers. - Register today! Save 20% off the price with discount code: LeeBoonstra.
SenchaCon.com

SenchaCon 2015 Lee Boonstra introduction! from Lee Boonsta on Vimeo.

Sencha Cmd for scaffolding Sencha Touch / EXT MVC project

Posted on in Environment Sencha Touch

Sencha's commandline tools (Sencha CMD) previous known as Sencha SDK Tools are really great! With one line in your terminal you can generate your MVC boilerplate.
From scaffolding a new project, to minifying and deploying your application to production, Sencha Cmd provides a full set of lifecycle management features to compliment your Sencha project.

First start downloading the Sencha CMD: http://www.sencha.com/products/sencha-cmd/download
Run the installer and remember the path where it's installed.

Let's start generating a MVC project for Sencha Touch. (You can use the same instructions for an EXT JS4 project btw, use the EXT library instead):

  1. Now open your terminal on Mac OSX (or Run > CMD on Windows).
  2. Test with the command: sencha if Sencha CMD is correctly installed.
    It should prompt you all the Sencha options & commands.
  3. Incase you don't see anything, you need to make sure sencha is added to the classpath.
    (On Mac OSX you can change this by opening, .bash_profile in your user folder. (hidden file). Add the following line: export PATH=/Users/username/bin/Sencha/Cmd/3.0.0.250:$PATH)

(Incase you don't have Sencha Touch yet, download it here and extract it in your project directory.)
4. Create a project folder. (for example MyApp)
5. Now let's start:
A. You have to be in the folder where Sencha Touch 2 is extracted.
B. Type the following command sencha generate app MyApp [path]
C. The MyApp name will be the name of your app, (note: this will be the App namespace later)

The command could look like this:

MyMacBookPro:touch2 lee$ sencha generate app MyApp XAMPP/htdocs/

Great, so now that you have a project, let's generate a model:
Specify the model name, and all the fields.

sencha generate model -name MyModel -fields fName,lName

Generate a form:

sencha generate form -fields [comma delimited list of fields] -name formName 

As you can see, you can almost generate everything.
To see an overview of what else you can generate type the following command:

sencha help generate

Always use semicolons in JavaScript

Posted on in JavaScript

According to Javascript; the semicolon after a statement (for example a function), is optional.
However, it's much better to end your line with a semicolon. A validator like JSLint for example, will throw a warning, even though
the browser won't and accepts it.

See below, which strange things can happen when you won't end your line with a semicolon.
Javascript errors because of the order of javascript functions mixed with jQuery plugins...
http://jsfiddle.net/bpsuW/11/

foo is a simple javascript function.
Baz is a simple self running jQuery plugin. (because of the parentheses surrounding it).

foo = function(){
alert("function 1"); 
}

(function(){
$.fn.Baz = function(opt){
alert("function 2");
}
})(jQuery)

See below the script, without strange javascript errors.
http://jsfiddle.net/bpsuW/10/

The answer is really logical.
Because there is no semicolon, the jQuery plugin (Baz) will directly execute, because of the parentheses.
Like it's a parameter of the javascript function you wrote before. (foo), and then throws errors.
So:

foo(Baz)

When you mix your jQuery plugins with native javascript classes and functions in different orders; these kind of errors can happen.
This scenario above shows you why you should always end your statements with a semicolon.

Make your mobile webapp work offline with application cache

Posted on in Mobile

This tutorial will help you to put your mobile webapp offline.

1. create your cache manifest file
create a file yourappname.manifest in your application root.
In the file enter all files you have to cache to make your app working offline.

For example the app.manifest file looks like this:

CACHE MANIFEST
#rev2

# Explicitly cached entries
CACHE:
index.html

img/icon.png
img/phone_startup.png
img/tablet_startup.png
img/main-image.png

css/ext-touch.css
css/default.css

js/ext-touch-debug.js
js/ext-touch.js
js/index.js

# Resources that require the user to be online.
NETWORK:
js/twitter.js

#If source in inaccessible serve other file. for example: /index.php /index.html
FALLBACK:

2. Add your manifest to your application .html file header
In your html file:



3. Create a .htaccess file and add expire configuration for your *.manifest file to your app root.


ExpiresActive On
ExpiresDefault "access"

4. Add type manifest to your apache config (apache.conf / vhost.conf or .htaccess file)

AddType text/cache-manifest .manifest

That's it, now your app should work offline. You should know that, as soon as the manifest file fails with caching the files. It stops. That means that the files will not be updated.

Use this code to check/swap cache via code:

var i = -1;

// Convenience array of status values
var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';

// Listeners for all possible events
var cache = window.applicationCache;
cache.addEventListener('cached', logEvent, false);
cache.addEventListener('checking', logEvent, false);
cache.addEventListener('downloading', logEvent, false);
cache.addEventListener('error', logEvent, false);
cache.addEventListener('noupdate', logEvent, false);
cache.addEventListener('obsolete', logEvent, false);
cache.addEventListener('progress', logEvent, false);
cache.addEventListener('updateready', logEvent, false);

// Log every event to the console
function logEvent(e) {
i=i+1;
var online, status, type, message;
online = (isOnline()) ? 'yes' : 'no';
status = cacheStatusValues[cache.status];
type = e.type;
message = 'online: ' + online;
message+= ', event: ' + type;
message+= ', status: ' + status;
if (type == 'error' && navigator.onLine) {
message+= ' There was an unknown error, check your Cache Manifest.';
}
log(i + ' ' + message);
}

function log(s) {
//alert(s);
console.log(s);
}

function isOnline() {
return navigator.onLine;
}

if (!$('html').attr('manifest')) {
log('No Cache Manifest listed on the tag.')
}

// Swap in newly download files when update is ready
cache.addEventListener('updateready', function(e){
// Don't perform "swap" if this is the first cache
if (cacheStatusValues[cache.status] != 'idle') {
cache.swapCache();
log('Swapped/updated the Cache Manifest.');
}
}
, false);

// These two functions check for updates to the manifest file
function checkForUpdates(){
cache.update();
}
function autoCheckForUpdates(){
setInterval(function(){cache.update()}, 10000);
}

More info's, can be found here:
http://developer.apple.com/library/safari/#documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html

Node Connect example

Posted on in JavaScript Node JS

The example below can be easily replaced with Node Connect. Just with a few lines.
app.js

var http = require('http');
var path = require('path');
var fs = require('fs');
var extensions = { 
   ".html" : 'text/html', 
   ".css" : 'text/css', 
   ".js" : 'application/javascript',
   ".json" : 'application/javascript', 
   ".png" : 'images/png', 
   ".gif" : 'images/gif', 
   ".jpg" : 'images/jpeg' 
} 

http.createServer(function(req, res){ 
   var filename = path.basename(req.url) || 'index.html', 
      ext = path.extname(filename), 
      dir = path.dirname(req.url).substring(1), 
      localPath = __dirname + "/views/"; 

     //console.log(localPath); 
     if(extensions[ext]){
        localPath += (dir ? dir + "/" : "") + filename; 
        path.exists(localPath, function(exists){ 
           if(exists){ 
              getFile(localPath, extensions[ext], res) 
           } else { 
              res.writeHead(404); res.end();
           } 
        }); 
     }
}).listen(8000, '127.0.0.1'); 

getFile = function(localPath, mimeType, res){ 
   fs.readFile(localPath, function(err, contents){ 
   if(!err){ 
      res.writeHead(200, { 
         "Content-Type" : mimeType, 
         "Content-Length" : contents.length 
      }); 
      res.end(contents); 
   } else { 
      res.writeHead(500); 
      res.end(); 
   } 
});

Now install Connect:

$ sudo npm install connect

app.js

var connect = require("connect");
connect().use(connect.static(__dirname + "/views")).listen(8000);

Hello World with Node.js

Posted on in JavaScript Node JS

See the example below for an easy Hello World example with Node.js. Create a Node.JS server and serve a hardcoded response, with content-type: “text/html”. And listen to localhost:8000 in your browser to see the result. In your project folder create an app.js file:

var http = require('http');
http.createServer(function(req, res){ 
   var html = BoilerplateHello World"; 
   res.writeHead(200, { 
      'Content-Type' : 'text/html', 'Content-Length' : html.length 
   }); 
   res.end(html);
}).listen(8000,'127.0.0.1');

With the above example you can’t create a real-life application. Let’s create an MVC folder structure in your project folder. By creating the following folders: “controller”, “model”, “views”. In the “views” directory, create here an index.html file. With the following content:

Then change your app.js file like the example below to retrieve the index.html file from the views folder:

var http = require('http');
var path = require('path');
var fs = require('fs');
http.createServer(function(req, res){ 
   var filename = path.basename(req.url) || 'index.html', 
   ext = path.extname(filename), 
   localPath = __dirname + "/views/"; 
   //console.log(localPath); 

   if(ext == ".html"){ 
      localPath += filename; 
      path.exists(localPath, function(exists){ 
         if(exists){ 
            getFile(localPath, res) 
         } else { 
            res.writeHead(404); 
            res.end(); 
         } 
       }); 
    }
}).listen(8000, '127.0.0.1'); 
getFile = function(localPath,res){ 
   fs.readFile(localPath, function(err, contents){ 
      if(!err){ 
         res.end(contents); 
      } else { 
         res.writeHead(500); 
         res.end(); 
      } 
});

Auto restart node after code changes

Posted on in JavaScript Node JS

When you are sick and tired of restarting your node app in the terminal (CTRL+C) on every code change you make then you can automate this process. Actually it’s really simple. Install Nodemon via the package manager.

$ sudo npm install nodemon -p

When you want to check if it correctly installed and on which version you are running Nodemon:

$ nodemon -v
0.6.14

Is everything correctly set? You can start Nodemon, by typing the following command in the root of your current node project. For example:

$ nodemon app.js
9 Apr 20:15:23 - [nodemon] watching: /Users/lee/Projects/nodejs/www
9 Apr 20:15:23 - [nodemon] starting 'node app.js'