Implementing Promises - Mastering JavaScript Promises (2015)

Mastering JavaScript Promises (2015)

Chapter 4. Implementing Promises

In the last chapter, Chapter 3, The Promise Paradigm, we have seen how promise and its theories were fabricated together to form a whole new amazing picture of the software engineering paradigm, and especially in today's modern asynchronous application development life cycle.

In this chapter, we will start experimenting on how this concept can take shape by implementing promises in real time. Why do we need to see its implementation? The answer to this question is quite simple; we need to see how the concept we have developed so far is true and how much of this concept is really applicable. Also, with these little implementations of promises, we will plot the base of our foundation to use promise in other technologies in later chapters. So, let's see how we will go about with this implementation phase.

How to implement promises

So far, we have learned the concept of promise, its basic ingredients, and some of the basic functions it has to offer in nearly all of its implementations, but how are these implementations using it? Well, it's quite simple. Every implementation, either in the language or in the form of a library, maps the basic concept of promises. It then maps it to a compiler/interpreter or in code. This allows the written code or functions to behave in the paradigm of promise, which ultimately presents its implementations.

Promises are now part of the standard package for many languages. The obvious thing is that they have implemented it in their own way as per the need. We will be examining more on how these languages are implementing the concept of promise in detail in this chapter.

Implementations in Java

Java is among the world's favorite and most admired programming languages and is used in millions of devices across the globe. There is no need to say anything further about Java, except that it's the first choice of engineers when it comes to creating application software that uses multithreaded and controlled asynchronous patterns and behaviors. Java is one of the few languages that has implemented asynchronous behavior by default in its compiler, which helps programmers to write robust, scalable, and maintainable pieces of software.

The util package of Java

Naturally, Java has more acceptability for the concept of promise and its implementation. There are many implementations in the package of java.util.concurrent, regarding promise and its implementations. We have handpicked some of the interfaces and classes that are helping out in implementing promises or nearly matching the concept.

The mechanics of Java to implement a promise

Within the java.util.concurrent package, there are a number of interfaces and classes that will help us to write concurrent and asynchronous code, but there are a few particular interfaces and libraries that are specific to this promise/future implementation.

The java.util.concurrent package is home to concurrent programming (as the name says) and is the home of few small standardized extensible frameworks. This also helps in implementing some of the core classes, which in normal conditions, are hard to work with.

The core components of java.util.concurrent

The java.util.concurrent package has many classes and components, but some of the core components that make this particular package more adaptable to work are:

The core components of java.util.concurrent

Core components of the Java util.concurrent package

Executor

Executor is a simple standardized interface, which is commonly used to define custom threaded subsystems. These subsystems include the thread pools, asynchronous I/O, and task-based lighter frameworks.

Tasks created in the thread can either be executed in "the same task-execution thread" or in a new thread; this may also be executed in the thread calling execute sequentially or concurrently. Whichever thread the execute pattern task adopts is purely based on the concrete Executor class used.

The ExecutiveService interface provides a fully stacked asynchronous tasks framework. This interface is for a number of tasks of the pool, which includes the controlled shutdown of Executor, managing of different in-pool cues, and scheduling of tasks. There are a few more associates that work with ExecutiveService to add support to delay the periodic and periodic task executing. One such associate is ScheduledExecutorService, a subinterface that works with the ExecutiveService interface in managing the delayed and periodic tasks executing whenever called upon.

There is another interface called the ExecutorService interface, which provides methods to arrange the execution of any function that is expressed as callable.

Queues

When it comes to the queue, the only thought that first emerges is the pattern of First In First Out (FIFO). Just as other languages apply this data structure in their own ways, Java treats it as an efficient and scalable thread-safe, nonblocking FIFO queue by employing the ConcurrentLinkedQueue class from its java.util.concurrent package. In the same package, five implementations support the BlockingQueue interface.

The BlockingQueue interface is a queue, which has an advanced wait mechanism. This holds the queue to further get into processing until all the previous processing is done. This also waits for the space to make the queue available when storing an element.

The five implementations of the BlockingQueue interface are listed as follows:

· LinkedBlockingQueue

· ArrayBlockingQueue

· SynchronousQueue

· PriorityBlockingQueue

· DelayQueue

We will discuss some of these relevant implementations in the following section.

Timing

Since util is the utilities package, it has controls in the form of classes and interfaces that help engineers to make use of their daily routine stuff. One such package is the timing of a method or interface. This is to perform certain instructed operations, and eventually, they time out themselves once the operation is done.

Most of us are already aware of the importance of session creation and session timeout, especially those of us who are programmers for the Web. Session tracking is a subject in its own and doesn't really link that much from the structure of this chapter, so we will return our focus to the topic of timing.

This packing is like a timing belt of Java programs. In any engine, the role of a timing belt is to make sure that certain mechanical operations are done within a specified amount of time; it is the same as with this package. This controls the in-time and out-time of functions and also the definite/indefinite waits. The point to remember is that all these methods use the time out in every case. This helps threads define the amount of time a method spends within a thread pool and saves the actual program to perform with scalability.

Synchronizers

Java provides a low-level thread creation and execution so that programmers can easily handle and modify the thread-level control. In earlier versions, the controlling of threads was considered the hardest topic to deal with, as there was much of the manual control than automation of threads and their synchronization. At this time, Java was much more advanced in controlling multiple threads than its competing languages, but still playing with threads was a fairly hard task for Java engineers.

In the later versions of Java, this problem was considered as the most important one to find a regulation, and finally, with the emergence of version 7, the compiler has fixed most of the problems faced by engineers.

In the current version, which is version 8, five classes aid the purpose of synchronization:

· The Semaphore class is a classic concurrency tool and has been around for a very long time (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html)

· The CountDownLatch class is a very simple yet common utility for blocking until a given number of signals, events, or operations being performed in other thread are being taken care off (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)

· The CyclicBarrier class is a resettable multiway synchronization point, which is useful in some styles of parallel programming (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html)

· The Phaser class provides a more flexible form of barrier that may be used to control phased computation among multiple threads (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html)

· The Exchanger class allows two threads to exchange objects at a rendezvous point and is useful in several pipeline designs (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html)

Concurrent collections

The Concurrent packages provide the implementations for a multithreaded context and has the following implementations.

Since it has more specific sync facilities, some of its classes use the prefix Concurrent to highlight the additional facilitates it is providing. A few more prominent ones are:

· ConcurrentHashMap

· ConcurrentSkipListMap

· ConcurrentSkipListSet

· CopyOnWriteArrayList

· CopyOnWriteArraySet

The virtue of concurrent collection is its safe thread, but not overlooked by a single locking mechanism, in particular. Only in the case of ConcurrentHashMap, it allows any sum of concurrent reads as well as concurrent writes. Why, then, do we use synchronized classes? The answer is that they are very useful in preventing all the access to a collection using a single lock, but it has a cost, and poorer scalability.

In other cases where multiple threads are in line to access a common collection, the current version of classes is more advisable, whereas unsynchronized locks are used when either collections are unshared or they can be accessed when holding other locks.

The implementation of promise by Java

Java implements the paradigm of promise using its promising class and interfaces. Although its asynchronous behavior is one of the core and flagship features of Java, here are the ingredients of how promise is implemented in Java:

· Interfaces:

· CompletionService

· ExecutorService

· Future

· Classes:

· Delayed

· DelayQueue

· FutureTask

CompletionService

The CompletionService interface acts as a service to make a distinction between new asynchronous tasks from the result of completed tasks. This follows a simple process in which the producer adds the tasks for execution. For the consumers, this interface takes completed tasks and processes their results in the order that they were marked as completed. This service can be used for many concurrent operations, such as managing an asynchronous I/O. The mechanism of an asynchronous I/O is the tasks that are submitted in one part of the program or set of programs or in a system, and then acted upon the different parts of the program. The submission order may be different than the order they were requested initially.

The mechanism of an asynchronous I/O is that it reads tasks and stores it in one part of the program, such as buffer.

This can be a single program (such as browser) or a set of programs (such as an operating system thread pool). The thread handler decides which thread needs to be executed first.

This interface relies on a separate executor or actually executes the tasks due to which the CompletionService interface only manages an internal completion queue. As interfaces implement, they need a class to do so, and the ExecutorCompletionService class provides such a facility.

ExecutorService

The ExecutorService interface has two main roles to perform—one is to provide methods to manage the termination of asynchronous tasks, and the other is to provide the methods that can produce a future value for tracing. This tracking can be done for either one or more asynchronous tasks.

The use of an Executor for ExecutorService:

· ExecutorService inherits Executor, which provides the methods to manage termination and production of a future value to track the progress.

· ExecutorService when shutdown rejects all the new tasks. They have been loaded with two different methods:

· shutdown()

· shutdownNow()

The shutdown() method allows the tasks in memory to conclude their states and then terminate them. Also, it prevents the memory from entering and processing it for any upcoming tasks. On the other hand, shutdownnow() doesn't give any such liberty; it just terminates whatever is in the memory, then and there. This also totally rejects the entry of new tasks in the memory by nullifying the existing thread.

Both the methods have their own significance, but since both are related to termination of existing tasks, they must be used with much care and with proper understanding of the potential consequences.

The following code snippet is taken from the original Java docs, which is available at http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html:

class NetworkService implements Runnable {

private final ServerSocket serverSocket;

private final ExecutorService pool;

public NetworkService(int port, int poolSize)throws IOException {

serverSocket = new ServerSocket(port);

pool = Executors.newFixedThreadPool(poolSize);

}

public void run() { // run the service

try {

for (;;) {

pool.execute(new Handler(serverSocket.accept()));

}

} catch (IOException ex) {

pool.shutdown();

}

}

}

class Handler implements Runnable {

private final Socket socket;

Handler(Socket socket) { this.socket = socket; }

public void run() {

// read and service request on socket

}

}

The following method shuts down an ExecutorService interface in two phases: first, by calling shutdown to reject incoming tasks, and then by calling shutdownNow(), if necessary, to cancel any lingering tasks:

void shutdownAndAwaitTermination(ExecutorService pool) {

pool.shutdown(); // Disable new tasks from being submitted

try {

// Wait a while for existing tasks to terminate

if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {

pool.shutdownNow(); // Cancel currently executing tasks

// Wait a while for tasks to respond to being cancelled

if (!pool.awaitTermination(60, TimeUnit.SECONDS))

System.err.println("Pool did not terminate");

}

} catch (InterruptedException ie) {

// (Re-)Cancel if current thread also interrupted

pool.shutdownNow();

// Preserve interrupt status

Thread.currentThread().interrupt();

}

}

Future

In Java, future represents the value of the result of an asynchronous computation. Methods are provided to track the status of result. These methods indicate whether the current state is waiting or not.

The catch is, you can only yield the result using get or when the computation is done.

Cancellation can be done via the cancel method; this sounds very easy to remember. Cancellation of a Future value can be done using the cancellation method.

You can also check whether the task was completed normally or cancelled by virtue of this method invocation. Once the computation is done, it cannot be cancelled; this sounds so promising to us, just like the concept of promise.

You can also use Future to cancel tasks. Although it's not a very good approach, if you want to do it, then you can declare many types of Future objects and ask the method to return null; that's it! You got your task cancelled once again. This must be done before the final computation of the tasks.

Here is the code snippet:

interface ArchiveSearcher { String search(String target); }

class App {

ExecutorService executor = ...ArchiveSearcher searcher = ...

void showSearch(final String target)throws InterruptedException {

Future<String> future

= executor.submit(new Callable<String>() {

public String call() {

return searcher.search(target);

}});

displayOtherThings(); // do other things while searching

try {

displayText(future.get()); // use future

} catch (ExecutionException ex) { cleanup(); return; }

}

}

The FutureTask class is an implementation of Future that implements Runnable, and so may be executed by an Executor. For example, the previous construction with submit can be replaced by the following:

FutureTask<String> future =

new FutureTask<String>(new Callable<String>() {

public String call() {

return searcher.search(target);

}});

executor.execute(future);

Delay and DelayedQueue

Delay is an interface that uses a marker to mark those objects that were acted upon, after they were given a delay.

DelayedQueue is an unbounded queue that is used to collect all the objects that were delayed/expired. Since it's a queue, it must have a header element whose delay has expired long ago.

Since it's a queue and is similar to a queue data structure, it has a starting point called header and an ending point called footer. When it comes to future, the queue we are referring to here has a value, which has already expired due to the failed promise or unfulfilled promise.

If such an element was not found, will the poll return null when the expiration occurs? Well, it occurs when the method getDelay(TimeUnit.NANOSECONDS) returns the value as less than or equal to zero. The expired elements in this way cannot be removed, so they are treated as normal ones.

FutureTask

FutureTask is the cancellable asynchronous computation. This is the basic provider of Future that is loaded with methods from start of a method to cancel it. This also helps in the retrieving of the result of the computation, and since it's an implementation, the result can be extracted when the computation has been completed. Needless to mention that once the result is computed, it cannot be pulled back or changed as it's a promise.

Summing up Java and Promises.js

If we conclude the preceding discussion, it's clear that Java has a clearer approach and implementation when it comes to Promises.js. It's a mature way of handling asynchronous behavior, and especially, the way it handles multithreading is far better than what other languages have to offer. However, as every implementation has its own drawbacks, Java too has it, and it's quite acceptable since you cannot just copy and paste the theory as it is with any compiler/interpreter. There are few more supportive frameworks/libraries contributed by an open source community to add the remainder of its implementation.

Say hello to JDeferred

Inspired by the implementation of promise in jQuery, few Java Engineers have started to develop a library called JDeferred. This implements the concept of promise as robustly as it should be by leaving the gaping holes of the java.util.concurrent package. This was a brief of how JDeferred works. Let's dive deep into what it is and its unique advantages, as compared to other implantations available in the market.

Just like jQuery has a deferred object, JDeferred is designed in a similar way to behave and contact with Java's compiler. JDeferred is not only similar with jQuery's implementation of promise, but it also extends its support to the Android Deferred Object. Chapter 8,Promises in jQuery is the dedicated chapter on jQuery and its mechanism and working on promise, so we can skip that part for now and see what the Android Deferred Object is, and how it fits into the implementation of promise.

A few words about Android Deferred Object

It would be unfair not to showcase the existence of Android Deferred Object and its properties when we are discussing JDeferred. The Android Deferred Object is a utility or more simply, it is a chainable utility object that can actually do all the same stuff for the Android domain. It can register multiple callbacks in a single callback queue; it can invoke callback queues and after processing. It also can relay the state of success or failure to whichever function is waiting for; it doesn't matter whether it's a synchronous function or an asynchronous function.

Its working is quite straightforward. You obtain a promise out of a function that was executed asynchronously. As we can work around with promise, you can attach callbacks to get notified about the success or failure. Whenever this piece of program that was working asynchronously finishes off as expected, the promise is called to be resolved in case of any error; it calls the rejected parameter.

Use case 1 – object success and failure callbacks for a task

Say that you need an asynchronous HTTP request. A simple way of using Android Deferred Object is to wrap the request in to DeferredAsyncTask and attach callbacks to your action. Here is the code for such a scenario:

new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {

protected abstract Resolved doInBackground() throws Exception {

//do your async code here

}

}

.done( new ResolveCallback<HttpResponse> {

public void onResolve(HttpResponse resolved) {

//your success code here

}

})

.fail ( new RejectCallback<HttpResponse> {

public void onReject(HttpResponse rejected) {

//your failure code here

}

});

The reference to preceding code is available at https://github.com/CodeAndMagic/android-deferred-object.

Use case 2 – merging several promises

This use case is best for when you need to add several executed promises into a single one by merging them as a single promise. A convenient way is to call the DeferredObject.when method:

Promise<A1,B1,C1> p1 = new DeferredAsyncTask<A1,B1,C1>() { ... };

Promise<A2,B2,C2> p1 = new DeferredAsyncTask<A2,B2,C2>() { ... };

Promise<A3,B3,C3> p3 = new DeferredAsyncTask<A3,B3,C3>() { ... };

//when gives you a new promise that gets triggered when all the merged promises are resolved or one of them fails

DeferredObject.when(p1,p2,p3)

.done(new ResolveCallback<MergedPromiseResult3<A1,A2,A3>() {

public void onResolve(MergedPromiseResult3<A1,A2,A3> resolved){

Log.i(TAG, "got: " + resolved.first() + resolved.second() + resolved.third());

}

})

.fail(new RejectCallback<MergedPromiseReject>() {

public void onReject(MergedPromiseReject rejected) {

//failure handling here

}

})

.progress(new ProgressCallback<MergedPromiseProgress>() {

public void onProgress(final MergedPromiseProgress progress){

//you get notified as the merged promises keep coming in

}

});

//Merging doesn't stop you do add individual callbacks for promises that are in the merge

p1.done(...).fail(...)

//Or even merging them in another way

DeferredObject.when(p1,p2).done(...).fail(...)

Mechanics of JDeferred

Coming back to our core discussion of JDeferred, there is almost everything that this implementation has adopted from promises and considered to be more promised than any other library. We will look at what the features it's providing are, and how they are implemented within.

Features of JDeferred

The implementation of JDeferred provides all the methods needed to present the promise paradigm in Java. This has features such as deferred objects and promise, promise callbacks, multiple promises, callable and runnable methods, and Java's generic support.

The following table summarizes the features, along with their available implementation:

Feature

Available implementation

Deferred object and promise

N/A

Promise callbacks

.then(…)

.done(…)

.fail(…)

.progress(…)

.always(…)

Multiple promises

.when(p1, p2, p3, …).then(…)

Callable and runnable wrappers

.when(new Runnable() {…})

Java generic support

Deferred<Integer, Exception, Double> deferred;

deferred.resolve(10);

deferred.reject(new Exception());

deferred.progress(0.80);

Playing with the code using JDeferred

We will now explore some of the common examples of this implementation, which are used most often. We will be looking at the following topics:

· Deferred object and promise

· Deferred Manager

· Runnable and callable

· wait() and waitSafely()

· Filters

· Pipes

Deferred object and promise

The following code will help you understand how JDeferred implements deferred objects and promise. This code has comments for a better understanding:

//creating new deferred object by calling method DeferredObject();

Deferred deferredObj = new DeferredObject();

//now its time to make some promise

Promise promise = deferredObj.promise();

promise.done(new DoneCallback() {

public void onDone(Object result) {

//some code here

}

}).fail(new FailCallback() {

public void onFail(Object rejection) {

//some more code

}

}).progress(new ProgressCallback() {

public void onProgress(Object progress) {

//some code here

}

}).always(new AlwaysCallback() {

public void onAlways(State state, Object result, Object rejection) {

//some code here

}

});

Deferred Manager

Deferred Manager is a simple way to manage your deferred objects. Call the default method of Deferred Manager, and then add the number of promises you want:

//create Deferred Manager's object

DeferredManager theDeferredManager = new DefaultDeferredManager();

// uncomment this to specify Executor

// DeferredManager theDeferredManager = new DefaultDeferredManager(myExecutorService);

//add and initialize number of promises

Promise pm1, pm2, pm3;

theDeferredManager.when(p1, p2, p3)

// or you can add here .done(…)

//or you can add the fail here using .fail(…)

Runnable and callable

Runnable and callable, which is as good as promise, can be used as follows:

DeferredManager theDeferredManager = new DefaultDeferredManager();

theDeferredManager.when(new Callable<Integer>()

{

public Integer call() {

// return something

// or throw a new exception

}

}).done(new DoneCallback<Integer>() {

public void onDone(Integer result) {

...

}

}).fail(new FailCallback<Throwable>() {

public void onFail(Throwable e) {

...

}

});

You can use DeferredCallable and DeferredRunnable if you want to do the following:

· Be notified about the progress made by the callable or runnable

· You want to make your Deferred object

Here is an example code:

final Deferred deferred = ...

Promise ThePromise = deferred.promise();

ThePromise.then(…);

Runnable runable = new Runnable() {

public void run() {

while (…) {

deferred.notify(myProgress);

}

deferred.resolve("done");

}

}

Extending DeferredRunnable:

DeferredManager theDeferredManager = …;

theDeferredManager.when(new DeferredRunnable<Double>(){

public void run() {

while (…) {

notify(myProgress);

}

}

}).then(…);

wait() and waitSafely()

The wait() and waitSafely() functions are the part of JDeferred that wants to assume the control of all asynchronous tasks. This is not recommended, but can be very useful in some cases:

Promise promise = theDeferredManager.when(...)

.done(...) //when done

.fail(...) // when fail

synchronized (p)

while (promise.isPending()) {

try {

promise.wait();

} catch (InterruptedException e) { ... }

}

}

The shortcut to the preceding code is as follows:

Promise promise = theDeferredManager.when(...)

.done(...)

.fail(...)

try {

promise.waitSafely(); //replaced waitSafely();

} catch (InterruptedException e) {

...

}

Filters

Here is the code that we will use for the filtration of promise and deferred objects:

Deferred d = …;

Promise promise = d.promise();

Promise filtered = promise.then(new DoneFilter<Integer, Integer>() {

public Integer filterDone(Integer result)

return result * 10;

}

});

filtered.done(new DoneCallback<Integer>{

public void onDone(Integer result) {

// result would be original * 10

Pipes

Pipes in JDeferred also act for the asynchronous computation of tasks within the ordered manner:

Deferred d = ...;

Promise promise = d.promise();

promise.then(new DonePipe<Integer, Integer, Exception, Void>() {

public Deferred<Integer, Exception, Void> pipeDone(Integer result) {

if (result < 100) {

return new DeferredObject<Integer, Void, Void>().resolve(result);

} else {

return new DeferredObject<Integer, Void, Void>().reject(new Exception(...));

}

}

}).done(...).fail(...);

d.resolve(80) -> done!

d.resolve(100) -> fail!

Ultimate JDeferred

As you have seen, it's a much more powerful implementation of Java using promise. Java is very powerful when it comes to implementing the promise paradigm.

Actually, Java itself has many powerful features, but when it comes to proper implementation, such frameworks help us out. Since they are community maintained, they have a problem in terms of quality, as you may find nontested and unverified code that can wasteyour time. However, JDeferred has almost identical implementation, compared to jQuery.

Summary

Within this chapter of the book, we have actually started our journey towards mastering the promise. This chapter covered why we are implementing promise and why we chose Java as the core of this chapter. Java has richer features than any other programming language and it's also tried very well to keep it more or less similar to the automation of asynchronous behavior. We explored the core components of Java's util.concurrent class in greater detail and by virtue of which we have seen many live examples from Java docs online. Since Java cannot implement the promise paradigm in whole due to the limitations that we have seen, an open source library that acts exactly the same as the promise's paradigm has prescribed it. JDeferred has cleared the rest of the doubts out of our minds by taking full advantage of implementing the core values of promise, such as future, deferred, and so on.

In the next chapter, we will carry out a more practical work to develop our understanding of promise with WinRT.