Transitioning from JavaScript API v1 to V2

At OpenFin, we strive to stay on the cutting edge of JavaScript and to enable our customers do the same. We are pleased to officially announce the release of v2 of the JavaScript API, which represents our commitment and a big step in that effort.

Our JavaScript API v2 now supports promises and async/await syntax instead of callbacks, resulting in substantial improvement in code writability, readability and error handling. It also includes improved event handling by enabling programmers to use event emitter methods such as “once”, “listenerCount” and “removeAllListeners” to avoid memory leaks.

How Do I Use the v2 API?

Starting in OpenFin version 9, the v2 API was injected into OpenFin windows by default and available under the fin global. The classes for the v2 API (such as Window, Application, System, etc.) are directly on the fin object instead of nested in fin.desktop like the v1 API. For the most part the API has the same methods as the v1 API, but returns a promise instead of utilizing a callback. Some of the other improvements are listed below.

V1 API (fin.desktop) Becomes the “Legacy API”

The v2 API replicates and improves on the functionality of the legacy v1 API. The v1 API will continue to be injected under the fin.desktop global, but we recommend transitioning to the v2 API for the benefits listed here.

Promise-Based Architecture

The v2 API is promise-based, representing a huge improvement over the callback-based v1 API. Given the Chromium browser architecture that OpenFin utilizes, our API’s are required to cross process-boundaries and must be asynchronous. OpenFin developers will find themselves chaining asynchronous calls and without promises can end up in “callback hell” (see images below). This is greatly alleviated by the v2 API’s promise-based handling of asynchronicity. Usage of async / await syntax is a further improvement enabled by the promise-based nature of the v2 API. Finally, error handling has been made much simpler with the use of promise.catch or try / catch when utilizing async / await.

Eventing

In the v2 API, each class that has OpenFin eventing inherits an EventEmitter. This enables developers to use typical EventEmitter methods such as once, prependListener, removeAllListeners, listenerCount, etc. that were not available in the V1 API. These methods make memory management easier for OpenFin developers. We also return a promise on relevant eventing methods that will only resolve once the subscription is in place in the browser-process, allowing developers to ensure that events are not missed.

Please note that these methods are all context-bound so will only affect events in a given OpenFin window.

Application lifecycle – start and quit

New API methods have been added in the v2 API around application lifecycle. The Application.start method both creates and runs an application. The Application.quit method now exits the application and cleans up the information from the internal state of the OpenFin runtime. The Application.start call replaces both Application.create and Application.run. Application.quit replaces Application.close. A new applicationOption called quitOnClose will default to true, resulting in the cleanup of state on any user generated close as well. As a result of state cleanup, applications that exit using quit will not show in calls such as System.getAllApplications.

Miscellaneous Other Improvements

autoShow defaults to true (lands in 10.66.40.*)

In the v1 API, the autoShow windowOption defaults to false on new Window creation. In the v2 API, the default value is true, which makes the window show up without calling Window.show. We made this change for ease of development purposes as we believe most windows are shown immediately upon creation. You can actively change the setting back to false in the windowOptions.

Waitforpageload defaults to false (lands in 10.66.40.*)

In the v1 API, waitForPageLoad defaults to true in windowOptions on window creation. In the v2 API, the default value is false. This makes the window show up faster by not waiting until all content is loaded. You can actively change the setting back to false in the windowOptions.

Nativewindow no longer on wrapped window object

We no longer include the native Window in the wrapped window object. We found that it created more problems than its usefulness as it exacerbated any memory leaks. The native window can still be accessed via normal browser methods.

wrap/wrapSync and Identity

Wrap now returns a promise to better conform with other v2 APIs. For developer ergonomics, wrapSync methods have been added. Wrap and other functions that took uuid and name arguments in the v1 API now take an Identity argument, which is an object with uuid and name properties.

userMovement replaces frame

We have replaced the word “frame” in calls such as Window.disableFrame, and events such as frame-disabled and disabled-frame-bounds-changing with “userMovement” as in Window.disableUserMovement, user-movement-disabled and disabled-movement-bounds-changing. We changed this due to confusion between these calls and the actual window frame that can be enabled or disabled in WindowOptions.

DefinitelyTyped officially supported

OpenFin officially supports TypeScript type definitions via DefinitelyTyped for the v2 API. To use these types use npm:

npm install -save-dev @types/openfin

NodeJs Support

The v2 API is also available as a standalone Node.js npm package under hadouken-js-adapter.

OpenFin with callbacks (v1 API)

function doWindowStuff() {
    const childApp = new fin.desktop.Application(appOptions, function () { 
        childApp.run(() => {
            const win = childApp.getWindow();
            const myWin = fin.desktop.Window.getCurrent(); 
            myWin.getBounds(b => {
                win.moveTo(b.right, b.top, () => {
                    win.joinGroup(myWin, () => {
                        win.show(() => {}, (error) => {
                            console.log("Error showing the window", error);
                        });
                    }, (error) => {
                        console.log("Error joining window group", error);
                    });
                }, (error) => {
                    console.log("Error moving the window", error);
                });
            }, (error) => {
                console.log("Error getting bounds", error);
            });
        }, (error) => {
            console.log("Error running application", error);
        });
    }, function (error) {
        console.log("Error creating application:", error);
    });
}

OpenFin with async/await (v2 API)

async function doWindowStuff() { 
    try { 
        const childApp = await fin.Application.start(appOptions);  
        const win = await childApp.getWindow(); 
        const myWin = await fin.Window.wrap(fin.Window.me); 
        const myBounds = await myWin.getBounds(); 
        await win.moveTo(myBounds.right, myBounds.top); 
        await win.joinGroup(myWin); 
        return await win.show(); 
    } catch(err) { 
        console.log(err); 
        return err; 
    }
}