Tuesday, January 26, 2016

Moving to Modularized Promises via Geolocation

This article is part of a web development series from Microsoft. Thank you for supporting the partners who make SitePoint possible.

Transitioning from Callbacks and Messaging to Promises

A while ago, my son wanted to sell lemonade by the side of the road. You know how the story goes: we went to the store, got supplies and made the lemonade. Then he and his little sister sat by the side of the road. It was quite a first day, as they pulled in around $90 in lemonade sales!
[author_more]
The only downside... all day long he kept coming inside to make sure his accounting was correct. “Dad, did I charge enough?”, “Dad does this look like the correct amount?”, “Dad will you go to the store and buy me more lemonade and cups?” At the end of the day the three of us talked through building an application that would help them keep track of their finances. They thought it would be great if other friends could use the application and also keep track of where they put their lemonade stands up, along with the number of sales they made.

Lemon-Aide application

The Problem

Thinking through the application a few things came to mind. First, within the browser we will need to interact with the Geolocation API to find the latitude and longitude of the device. This browser interaction is asynchronous by nature. Second, this functionality to locate a person should be reusable so it could be utilized in other projects. Third, we need to specify an architecture (e.g. callbacks, messaging or promises) for the main JavaScript code to interact with the modularized geolocation module.

All the examples I’ll show today were written in Visual Studio Code which is a lightweight code-editor for Mac, Linux, or Windows.

Where am I: Geolocation

All modern browsers support the Geolocation API and fetching a device location. The Geolocation API is callback based, meaning as developers we need to pass functions into the API that will be called when the API is done processing. Geolocation is asynchronous, meaning that it could take 100 milliseconds or 100 seconds… there is no way to know how long it will take. What we do know is that the functions passed in as callbacks will be executed when the browser has finished processing the Geolocation request.

Beginnings of Geolocation… geolocation demo

Geolocation demo

Geolocation is accessed via the window.navigator object. The geolocation.getCurrentPosition method takes 3 parameters. For simplicity we will only use the first 2 parameters; a function to be called when the device location is found (i.e. resolveLocation) and a function to be called when the device location is not accessible (i.e. rejectLocation).

A successful interaction… geolocation demo

Geolocation demo successful interaction

Notice @ line 10 the resolveLocation callback function is given a position object from the browser. Among other things this position object contains the needed latitude and longitude properties. They are accessed from the position.coords object.

Aw, rejection… geolocation demo

Geolocation demo rejection

The rejectLocation callback @ line 27 is given an error object from the browser. This error object contains error codes and error messages. The error codes are numeric, ranging from 0 to 3. The 4 different error codes are defined in the ERROR_TYPE_CODES inferred constant array @ line 30. It should be noted that an error with a type code of 0 or 2 have extra information, hence the errorMessage string concatenation of error.code and error.message.

Reuse: Revealing Module Pattern

In a future article we will talk in-depth about modules. For this conversation we will simply use the Revealing Module Pattern. It will allow us to encapsulate the geolocation interaction within a module that could be used in any project, including whatever you are currently working on.

Modules for encapsulation & reuse… revealing module pattern demo

Revealing module pattern demo

Let’s unpack this code inside out. The private/inner getLocationfunction @ line 12 will be the function that performs the geolocation lookup with browser. This private function is exposed via the Module API (i.e. the return block @ line 17). The return block is simply a JavaScript object for specifying the relationship between public methods and the private methods they hide.

Notice the inner getLocation and return block are wrapped in an Immediately Invoked Function Expression (i.e. IIFE). Most importantly an IIFE has a function that the browser invokes after it has been parsed. This invoking occurs via the () @ line 21. Secondly, a closure is formed due to the Module API being returned from the IIFE. This closure allows the state of the module (i.e. the function’s execution context) to live for the length of the entire application! This idea seems singleton-esque, as this module is only created once; however this is not the singleton pattern. Revealing modules are instantiated immediately after being parsed, whereas singletons are not instantiated until first use (e.g. their getInstance is invoked).

The guts of the revealing module pattern allows for the encapsulation of private variables that can only be accessed and changed via publicly defined getters and setters. In this location module the inner/private getLocation function is not directly accessible. Only via a call to the public DI.location.getLocation method will provide the ability to call the inner/private getLocation function scoped to the anonymous function.

Lastly, we create a namespace @ line 7. Within DevelopIntelligence we use DI as our namespace object. This allows all DevelopIntelligence code to be stored on only one object attached to the global JavaScript window object, minimizing the pollution of the global object.

Interacting with the external module… main calling code

Interacting with external module

The main.js JavaScript file calls the location module’s public getLocation method via the DI namespace which in turn executes the private getLocation method functionality.

Continue reading %Moving to Modularized Promises via Geolocation%


by Kamren Zorgdrager via SitePoint

No comments:

Post a Comment