Web Dev

May Conference Recap

by on Jun.03, 2013, under Web Dev

I had the pleasure of attending portions of Google IO, CSS Conf, and JS Conf and wanted to summarize my notes on these conferences. These are my own take aways and may not have been what the presenter intended. If I’m completely off base, please feel free to drop me a line. This is also not inclusive as there are only so many sessions that one can attend :)

Major Trends

Componentization

Biggest theme of all of these conferences was attempting to create ways of compoentizing our code so that we can leave the smell of the poo all in one place, to paraphrase @danwrong.

Polymer

Google has the Polymer framework which polyfils web components. The premise is that you can create truly isolated components that are drop in and do not have worries such as CSS impact from other components.

<element name="my-element">
  <section>
    I'm a my-element!
  </section>
  <footer>nothing to see here</footer>
  <script>
    // When <element> is in document, might run in wrong context.
    // Only do work when this == <element>.
    if (this !== window) {
      var section = this.querySelector('section');
      this.register({
        prototype: {
          readyCallback: function() {
            this.innerHTML = section.innerHTML;
          }
        }
     });
    }
  </script>
</element>

This looks pretty amazing and I think will provide some awesome separation of concerns between content and behaviors in the future. Polyfilling this behavior seems outright genius but at the same time scares me as you are basing a lot of your implementation on something that is being hacked into the browser.

I’m of the opinion that this is amazing future looking work but is a bit more risk than I’d like to take on for my user base.

With standards support for this moving forward I think this is where we will be in 5-10 years depending on the user base that a project is required to support. I also believe that there is a huge opportunity here for developer tooling as this changes some things up that will require changes and improvements to our existing hint/test/minimize/etc tool stacks.

React

Facebook is doing similar work with their React framework. They have created a new compiled to JavaScript language that allows one to embed html into the source file:

var HelloMessage = React.createClass({
  render: function() {
    return <div>{'Hello ' + this.props.name}</div>;
  }
});

The framework will then manage the all of the rendering lifecycle without data binding or blanket re-rendering. This is apparently done by a DOM diffing algorithm that walks the DOM tree and updates only the components that need to be on a property change. The presenting team highlighted that you can provide hints to this implementation to improve performance so I do question how well this scales.

I have not had a chance to play around with this implementation but I am not against the html embedded in a JavaScript file like many people in the blogosphere are/have been. I think both this and polymer tackle separation of concerns in a different manner than the HTML/CSS/JS paradigm that has been beat into web developers for so long. I see them as implementing separation of concerns at a content vs. behavior level which may be better for some workflows.

Flight

Flight from Twitter attempts to handle componetization at a much smaller level. They focus on defining interfaces between discrete components. Each of these components can focus on only their implementation.

This is lower-level than the systems above and in many ways can be used to build other framework systems.

Performance

Performance was a huge concern at all 3 conferences with many sessions devoted to different aspects of performance improvements. My major take aways are:

  • Don’t follow a coding pattern because something is “faster”. What exactly is faster will change as runtimes optimize for the code that they are seeing. Instead look at what the tools are saying and react accordingly.

  • Don’t prematurely optimize. You are probably wrong. Your code is most likely going to be harder to understand and there is plenty that you can spend time as engineering time is finite.

  • Performance is holistic.

    • JavasScript, layout, rendering, compositing, GC, etc. can all impact performance.
    • Newer architectures are moving behaviors out to other threads but this does not work if you try to implement your own behavior. Custom scrolling is the biggest offender here.
    • Under current Chrome implementations touch handlers can cause scrolling issues as it disables certain scrolling optimizations.
  • Chrome is the leader in debugging tools and ability to investigate performance

    • Chrome dev tools timeline panel
    • about:tracing – Google’s internal performance tool
    • V8 tools – In depth V8 profiling tools
    • Continuous painting mode lets you test performance impact of specific elements or properties
    • Remote debugging API (This powers Chrome for Android debugging and topcoat performance monitor)
  • Higher level console commands are useful

    • console.time
    • console.group
    • These are not always evil and can help programmers with onboarding
  • Topcoat has a turbo mode which attempts to remove layout and style calculation from overhead. All elements have style element and are absolutely positioned. On a personal note this seems a bit overboard for 99% of use cases.

  • High-speed cameras can be used in the name of performance testing! :)

Many V8 specific performance recommendations as well:

  • V8 has an optimized/unoptimized state machine that a particular piece of code may jump between. Can’t tell at compile time if something will be promoted to optimized once hot. When profiling should look for * token next to function names to verify that it’s optimized.

  • Memory allocation pattern between optimized and unoptimized are dramatically different. Optimized will often remove temp variables wereas unoptimized will have to GC temp variables.

  • Can monitor state machine with --js-flags="--trace-deopt --trace-opt-verbose". WARN: Very verbose. Pipe & Grep

Better Tooling

Adobe and Google had strong developer tools showings at these conferences.

Adobe demoed some very cool features for their brackets IDE including:

  • PSDLens – PSD inspector assistant
  • Response – Responsive design editor
  • Theseus – Brackets debugger concept
  • Instabug – Live code inspector with visual unit test executor/generator

Additionally they covered some of the tools involved with their topcoat project:

On the Google front, most of the improvements were in the Chrome Developer Tools including:

  • Flame charts
  • Full remote dev tools on Chrome For Android
  • SASS support, generically via source maps
  • Live editing with mapped update support

JavasScript everywhere

One of the other fun themes was the use of JavaScript in more and more places. This included a hacking day on various bots and AR Drones for those who choose those sessions. This culminated with a Nodebot shooting down a NodeCopter and calls for Node-based Aircraft Carriers.

Random Coolness

  • jankfree.org
  • nodesecurity.io
  • webplatform.org
  • @rem demoing game with RTC and getUserMedia
  • @seb_ly giving an amazing presentation including crowd participation from 5000 miles away and live coding over VNC
  • @necolas – Get over yourself. Tech changes every few years and all of the battles today will likely be moot in a few years.

Outside of the above there we’re a lot of fun and interesting sessions that could be discussed in depth but suffice to say that the JavasScript and Web Development communities are very strong and there is a lot of interesting stuff coming down the pipes.

Comments Off on May Conference Recap :, more...

Lumbar: Modular Javascript Build

by on Jan.17, 2012, under Web Dev

Since joining @WalmartLab’s mobile web team close to a year ago we have been very busy rebuilding the mobile web platform using Backbone, Handlebars, Stylus and other awesome open source tools and frameworks.

Even though these tools allow for some pretty impressive feats of javascript, we kept hitting inefficiencies both in execution and developer time due to resource loading and management.

When dealing with handlebars for example, we consistently found that we were trying to fight against the system to manage the templates used by a view. We neither wanted to manually inline the template in the javascript as we all know that escaping a language within a language is just painful, ala Java running SQL, nor did we want to add the additional overhead of an additional request for deferred loading of templates or worse inlining all application templates within the html file.

Being both constrained by the mobile environment and needing to operate at the scale of Walmart it became apparent very quickly that we needed to have some sort of build-time utility to manage this so the developer can focus on creating the application logic, throw it into the build tool and out comes a nicely optimized module of code and styles.

Lumbar along with the associated Lumbar projects such as lumbar-loader and lumbar-long-expires are the fruits of these efforts.

Overview

The Lumbar suite focuses on the management of all resources required to generate complex javascript applications across many different platforms and environments. It’s primary goals are to easily package, optimize, link to resources such as javascript, html, templates, styles, images, and any other client-side resources that web application may require.

From it’s initial implementation, Lumbar has focused on making client performance the number one goal, to this end it allows for chunking resources into distinct code modules, easy minification, inlining, and cache management.

Configuration

Lumbar is configured through a simple JSON config file, defining modules which are simple, demand loaded, segments of the application.

A base module that loads the core application:
    "base": {
      "scripts": [
        {"src": "js/lib/zepto.js", "global": true},
        {"src": "js/lib/underscore.js", "global": true},
        {"src": "js/lib/backbone.js", "global": true},
        {"src": "js/lib/handlebars.js", "global": true},
        {"src": "js/lib/thorax.js", "global": true},
        {"src": "js/lib/script.js", "global": true},
        {"src": "js/lib/lumbar-loader.js", "platform": "web"},
        {"src": "js/lib/lumbar-loader-standard.js", "platform": "web"},
        {"src": "js/lib/lumbar-loader-backbone.js", "platform": "web"},
        "js/init.js",
        {"src": "js/bridge.js", "platforms": ["iphone", "ipad", "android"]},
        {"src": "js/bridge-android.js", "platform": "android"},
        {"src": "js/bridge-ios.js", "platforms": ["ipad","iphone"]},
        {"module-map": true}
      ],
      "styles": [
        "styles/base.styl",
        {"src": "styles/iphone.styl", "platform": "iphone"},
        {"src": "styles/android.styl", "platform": "android"},
        {"src": "styles/ipad.styl", "platform": "ipad"},
        {"src": "styles/web.styl", "platform": "web"}
      ],
      "static": [
        {"src": "static/#{platform}/index.html", "dest": "index.html"}
      ]
    },

A router-linked module. When using backbone/thorax integration, this module will automatically load when the # or #hello routes are navigated:
    "hello-world": {
      "routes": {
        "": "index",
        "hello": "index"
      },
      "scripts": [
        "js/views/hello-world",
        "js/routers/hello-world.js"
      ],
      "styles": [
        "styles/hello-world.styl"
      ]
    }

This config file also defines the platforms that lumbar will generate, allowing for customizing the modules for different environments ("platforms": [ "android", "iphone", "ipad", "web" ]). At @WalmartLabs we utilize this to serve customized experiences for the native clients utilizing the same codebase.

Walmart Checkout Designs

Single stylus codebase styled for iPhone, Android, and mobile web platforms.

Walmart Checkout - iPad

More dramatic customizations of the same codebase utilizing platform conditional code.

The final component of the configuration is the packages component, which allows for bundling specific modules into singular responses when a particular use case only uses a subset of modules, such as the native checkout implementations utilized by @WalmartLabs.

  "packages": {
    "web": {
      "platforms": [ "web" ],
      "combine": false
    },
    "native-hello-world": {
      "platforms": [ "android", "iphone", "ipad" ],
      "modules": [ "base", "hello-world" ],
      "combine": true
    }
  },
Package declarations defining normal loading for web and combined for native platforms.

On building this will generate the following structure:

    $ find . -type f
    ./android/index.html
    ./android/native-hello-world.css
    ./android/native-hello-world.js
    ./android/native-hello-world@1.5x.css
    ./ipad/index.html
    ./ipad/native-hello-world.css
    ./ipad/native-hello-world.js
    ./iphone/index.html
    ./iphone/native-hello-world.css
    ./iphone/native-hello-world.js
    ./iphone/native-hello-world@2x.css
    ./web/base.css
    ./web/base.js
    ./web/base@2x.css
    ./web/hello-world.css
    ./web/hello-world.js
    ./web/hello-world@2x.css
    ./web/index.html

Which can be deployed as static resources to any web server, served via a CDN, or distributed by many other means.

While not a core feature, the lumbar-long-expires plugin takes this a step further by allowing resources to include expires tokens in their names automatically. When enabled the above may generate content like the following, allowing for the application resources to be served with extended Expires headers.

    $ find . -type f
    ./android/cb188f8/native-hello-world.css
    ./android/cb188f8/native-hello-world.js
    ./android/cb188f8/native-hello-world@1.5x.css
    ./android/index.html
    ./ipad/cb188f8/native-hello-world.css
    ./ipad/cb188f8/native-hello-world.js
    ./ipad/index.html
    ./iphone/cb188f8/native-hello-world.css
    ./iphone/cb188f8/native-hello-world.js
    ./iphone/cb188f8/native-hello-world@2x.css
    ./iphone/index.html
    ./web/cb188f8/base.css
    ./web/cb188f8/base.js
    ./web/cb188f8/base@2x.css
    ./web/cb188f8/hello-world.css
    ./web/cb188f8/hello-world.js
    ./web/cb188f8/hello-world@2x.css
    ./web/index.html

The @WalmartLabs mobile team believes strongly in open source software which is why in addition to open sourcing Lumbar we are also open sourcing our Thorax framework. If you are a backbone user looking to ease common tasks such as data binding and linking data operations to a particular route I urge you to take a look. It even integrates with Lumbar!

Comments Off on Lumbar: Modular Javascript Build :, , , , more...

Firediff 1.1.2

by on Mar.21, 2011, under Firediff, Firefox, Web Dev

Just in time for the impending Firefox 4.0 release, Firediff has been updated to version 1.1.2. This release contains compatibility changes for Firefox 4.0 and Firebug 1.7 as well as the ability to sort CSS properties alphabetically.

As always, the latest version is available here and is currently under review at AMO.

2 Comments :, , more...

Firediff 1.1.1

by on Dec.22, 2010, under Dev, Firediff, Firefox, Web Dev

Firediff has been updated to 1.1.1 on the incaseofstairs servers. This version is a minor bug release that fixes the Save Diff and Snapshot functionality.

Updated package is available here and is under review at AMO

Thanks to Borris and Joel for letting me know about this issue. Feel free to contact me with any other issues you may have found.

Comments Off on Firediff 1.1.1 more...

Cross Platform Text-Indexer

by on Nov.25, 2010, under Web Dev, webOS

While working on a recent Facebook release we ran into a performance bottleneck within the Mojo.Format.runTextIndexer API. Performance on device was on the order of a couple of seconds to process the content for feed items 30-50. This combined with the other tasks in the formatting and rendering cycle led to poor performance in the news stream.

For those who are not familiar with the Mojo.Format.runTextIndexer API, this API scans human generated text for URLs, phone numbers and email addresses, replacing the plain text representation with HTML links to the particular object. Additionally this API will replace emoticons with image representations on supporting platforms.

With the news stream scene being the primary scene in the application it was vital that we make this as performant as possible so I spent some time profiling this and determined that the bulk of the time in this operation was spent in the generic C indexer logic. Since at it’s core this is just a text scanning heuristic that, for the most part, does not rely on any C-level constructs, I decided to investigate a Javascript implementation to see if this would be more performant.

The result was a Javascript implementation that was many magnitudes faster than the core implementation (multiple seconds vs. ~10ms for a variety of Facebook news feeds), allowing for much faster execution as well as the creation of the library being released today.

While this library is designed primarily for webOS applications, it has also been designed to work in cross-platform environments for all functionality other than the emoticon replacement which requires platform specific logic to determine the proper image to replace.

Implementation

There are two key components to this implementation, the cross platform link indexer and the platform specific emoticon processor.

The link indexer is a two-stage regular expression, using the quite daunting INDEXER_REGEX regex to extract possible linker tokens with Javascript being used to determine the meaning of each token (or throwing it out just text content).

The emoticon processor is implemented by scanning for known, or possibly known, emoticons using the EMOTICON_REGEX regex and then passing these tokens to the platform’s text indexer implementation. Doing this allows for our own custom implementation while retaining the look and feel of emoticons used by the rest of the platform. For non-Mojo platforms this logic is disabled and emoticons will be left unmodified, with minimal change.

Warnings

HTML Content

Like the API this aims to replace, this API does not handle HTML context when replacing content. As a consequence this algorithm can break HTML content. In order to prevent this, the input and outputs for the TextIndxer.run API should be considered text or minimal HTML that will not match any of the replacements.

It is still possible to use this with content containing HTML by processing in a manner similar to the following although the input still needs to be filtered for XSS and other security concerns.

        var srcText = $(this).val(),
            womb = $("<div>" + srcText + "</div>");

        womb.contents()
            .filter(function() {
                return this.nodeType === Node.TEXT_NODE;
            })
            .each(function() {
                var text = $(this),
                    indexedText = TextIndexer.run(text.text()),
                    womb = $("<div>" + indexedText + "</div>");
                womb.contents().each(function() {
                    text.before(this);
                });

                text.remove();
            });

        $("#previewContent").html(womb.html());

Framework Override

By default this library overrides the Mojo.Format.runTextIndexer API (when used within the Mojo framework). Care should be taken with each OS upgrade to ensure that this override does not break any expected behavior. If uncomfortable with this override then it can be removed by removing these lines from the library and using the TextIndexer.run API directly.

    // Mojo Framework override. Unused on non-Mojo platforms and may be removed if undesired in Mojo apps
    if (window.Mojo && Mojo.Format) {
        // Override the Mojo API if it exists in this context.
        Mojo.Format.runTextIndexer = TextIndexer.run;
    }

Code

The code is available on Github within the text-indexer repository. A cross-platform live demo is also available here.

3 Comments :, , , more...

jsPerf

by on Aug.01, 2010, under Web Dev

Recently heard about the relatively new jsPerf service that Mathias Bynens has created and after spending some time playing around with this on my own machine I can honestly say that I love this service. Rather than a few gushing tweets on the subject, I felt like this deserves a blog entry covering it’s coolness.

The thing that I found the most striking about the site (and most likely the reason that I am writing this now) is that it broke many of my previous assumptions about performance of specific statements and relative performance of different platforms. Is innerHTML faster than DOM manipulation when generating a DOM tree? Not for a specific (relatively simple) construct under Chrome (OS X v5). Is array.join(”) the fastest way to concat a string. On my test platforms (OS X Firefox, Safari, Opera, Chrome release versions), nope.

Being a public playground, the community benefits from the collective knowledge. Scanning through the test list I saw many of the problems that I have run into before as well as some I had never considered such as the multiple methods of performing a Math.floor operation. While some of these honestly scare me and remind me of Kernel code, it’s good to know they exist.

jsPerf has full support for mobile browsers as well, meaning that you can test performance test the various algorithm options on device and have a realistic view of how it will behave on the device. In running some of the tests on a webOS device there were some quite distinct differences between comparable environments on a desktop class machine.

As with any performance testing I would recommend running these tests multiple times on your target device(s) before selecting a particular path to use as there are many things that could cause a single test to provide inaccurate results for a given execution, particularly on the more resource constrained environments.

Great job Mathias and can’t wait to see what features are added to this as well as the content that the community creates!

1 Comment :, more...

border-image-generator: Local File Access

by on May.31, 2010, under border-image-generator, Web Dev

This article covers the techniques used to implement the local file access feature that is included, along with tiling support, alternate styling, and parameter optimization, in the most recent push to border-image-generator.

One of the biggest short comings that I felt like border-image-generator was that all files had to be posted on a HTTP server due to restrictions on the access to the file:// protocol. In my personal workflow this was somewhat of a pain, so I set out to find a way around this issue.

During the design of this feature, I quickly decided that all data must remain on the client as I did not want to upgrade my hosting service to include more bandwidth, felt like responsiveness could be a concern, and do not want to tangle with the potentially messy privacy issues that could arrise from storing user generated images on my server.

While this sounded like a daunting task, it turns out that this was possible, in sufficiently advanced browsers, using a variety of HTML5 techniques, including Data URIs, the File API and the Web Storage API.

Display

The problem of displaying the image was the easiest to solve as all of the targeted browsers support data URIs as part of the border-image property. This allowed the application to generate URLs like the following

    border-width: 46px;
    border-image: url("data:image/png;base64,iVBORw0KGgoAAA....") 46 stretch;

And operate as expected. Data URIs have been covered fairly extensively elsewhere, so I will leave this to the reader to investigate.

Reading

With the actual display issue solvled, there was still the non-trivial issue of actually loading the content. My initial investigations involved Flash, which provides FileReference.load API which allowing for this functionality, but under the version I was testing on this API is only usable if invoked in response to user input. Being a HTML guy and lacking functional knowledge of the Flash development process I quickly ruled this technique out.

Continuing my research I came across an article on MDC that covered this exact use case, using the draft File API specification. This worked like a charm, even exposing the ability to read the image contents directly into a data URI.

The API is very clean for use cases such as this:
function loadFile(file) {
    var reader = new FileReader();
    reader.onload = function(event) {
         updateImageURI(file.name, reader.result);
     };
     reader.readAsDataURL(file);
}

Where the file variable above is a File object retrieved from a

<input type="file">
or the dataTransfer object passed to the drop html event.

        $("body").bind("dragenter dragover", function(event) {
            // We have to cancel these events or we will not recieve the drop event
            event.preventDefault();
            event.stopPropagation();
        });
        $("body").bind("drop", function(event) {
            event.preventDefault();
            event.stopPropagation();
            var dataTransfer = event.originalEvent.dataTransfer,
                file = dataTransfer.files[0];

            loadFile(file);
        });
        $("#localImage").bind("change", function(event) {
            var file = this.files[0];

            loadFile(file);
        });

This unfortunately is not without it’s issues. The File API is very much bleeding edge at this point and support is somewhat limited. As of this writing Firefox is the only browser which features this in production (Version 3.6). Support landed in the WebKit trunk literally earlier this month and can be used in their nightlies, but so far has not made it into any production releases.

The site is currently designed to progressively enhance as it detects support for the File API, so no need to worry about being left out of the site as a whole if you are not on one of these browsers yet.

History

After loading the content using the File API, the original implementation utilized the same #hash storage method for the data URIs, but this proved to be problematic as these strings can become quite large and interacting with these URLs was unwieldily. Needing another data store and being forced to maintain a cache of all local images due to the security model employed by the File API, we were left the options of storing all data in Javascript space or using the new Web Storage APIs implemented as part of HTML5.

Examining both options it seemed the the best course was to utilize the sessionStorage object when available and fail over to the javascript data model when not.

    // Check for browser support of session storage and that it is accessible
    // This may be inaccessible under certain contexts such as file://
    function supportsSessionStorage() {
        try {
            return !!window.sessionStorage;
        } catch (err) {
            return false;
        }
    }
    var localDataBinding = (function() {
        if (supportsSessionStorage()) {
            // If they support FileReader they really should support storage... but who knows (With the exception of file://)
            return {
                storeImage: function(name, data) {
                    var entryId = (parseInt(sessionStorage["imageList-count"])||0)+1;
                    sessionStorage["imageList-count"] = entryId;
                    sessionStorage["imageList-src-" + entryId] = data;
                    sessionStorage["imageList-display-" + entryId] = name;
                    return entryId;
                },
                getImage: function(entryId) {
                    return { src: sessionStorage["imageList-src-" + entryId], displayName: sessionStorage["imageList-display-" + entryId] };
                }
            };
        } else {
            // Fail over to plain js structures, meaing that refresh, etc will cause failures.
            var cache = [];
            return {
                storeImage: function(name, data) {
                    cache.push({ src: data, displayName: name });
                    return cache.length-1;
                },
                getImage: function(entryId) {
                    return cache[entryId];
                }
            };
        }
    })();

Working with this API it seems as though it is still somewhat rough. The vendor documentation all state that supported datatypes are only string values (Mozilla, WebKit), but the spec implies that this will change be final release and allow for storage of a much broader set of datatypes.

A consequence of this design is that boomark and URL sharing for local files is not a possibility. For users who need to share or store application states the image in question will need to be stored on a HTTP server and accessed by this route.

These changes as well as some incremental changes have been pushed live on border-image.com and are available in the github repository.

1 Comment :, , more...

Javascript Operation Queue

by on May.28, 2010, under Dev, Palm, Web Dev, webOS

When developing for a platform that relies on asynchronous APIs, such as webOS, the application logic frequently will need to block on a given operation prior to executing other dependent components. This may include anything from loading user data after authentication to saving data after initialization of a given data structure among others.

One method of handling this problem is to make the blocker component explicitly aware of the dependent components and the unique interface to each component, which works for simple cases or situations where the dependent to blocking relationship is one-to-one, but this quickly becomes complicated as a number of dependent components grows. In the extreme cases the blocker may have to be aware of significant portions of the system, leading to maintenance concerns.

Alternatively the blocker call can allow dependent components to register their interest in the completion of the operation and upon completion the blocker can simply notify the components on this list in a generic fashion. This allows that components to remain loosely coupled and has the added benefit of allowing for run-time conditional relationships without requiring that the blocker be aware of the state of the dependent.

Implementing such a notification system is fairly straightforward in Javascript: Simply collect waiting callbacks in an array or other structure then executing each upon completion of the blocking call.

Library

While simple to implement, my experience onFacebook for webOS has shown that a library to implement this behavior is worth the initial effort as manually writing nearly identical for loops over callbacks for the umpteenth time becomes tedious and error-prone.

To this end, we developed and open sourced the OperationQueue class which provides a common implementation that doesn’t require far too many for loops :)

Usage

To use the OperationQueue class you simply need to enqueue your dependent operations using the queue API.

queue can accept a single function which will be called upon successful completion.

    opQueue.queue(function(result) {
        // Do something with the data that we were waiting for!
        console.log("Blocking Operation Completed!");
    });
It also accepts an object with any combination of onSuccess and onFailure fields who will be called for each respective event.
    opQueue.queue({
        onSuccess: function(result) {
            // Do something with the data that we were waiting for!
            console.log("Blocking Operation Completed!");
        },
        onFailure: function(result) {
            console.log("Blocking Operation Failed");
        }
    });

These calls may occur at anytime. If the blocking operation has already completed then calls to queue will result in immediate execution of the queued operation. In this case the result object will not be included.

For the blocking call itself the getSuccessHandler and getFailureHandler generators will return callback functions that may be used to directly on completion or may be passed as callback handlers to the async API. These methods also accept a function parameter which will be called prior to their completion.

Used directly:
(opQueue.getSuccessHandler())();
As a callback:
ServiceRequestWrapper.request('palm://com.palm.preferences/systemProperties', {
        method:"Get",
        parameters:{"key": "com.palm.properties.nduid" },
        onSuccess: opQueue.getSuccessHandler(function(response) {
                Mojo.Log.info("Device ID: %j", response);
            }),
        onFailure: opQueue.getFailureHandler()
    });

For more complicated use cases, the reset function allows for enabling and disabling queuing at any time. For example, if you need to initially allow all operations to proceed and then block only while a given operation is in progress, the getSuccessHandler API may be called immediately after instantiation of the queue and then reset called prior to execution of the blocking operation.

Source:

Operation queue is available in the webos-samples repository on github, within the tipsAndTricks subproject.

One final note: While this was written for a webOS application, it does not depend on any webOS-specific constructs and may be used in any Javascript environment. To see it in action, check out the demo in any browser!

Comments Off on Javascript Operation Queue :, , , , more...

Visit our friends!

A few highly recommended friends...