DojoFAQ

In JavaScript it is common to use a Promise as a placeholder for a value which will eventually be provided upon completion of some operation. However most JavaScript methods run synchronously and immediately return a value. Dojo’s when module provides a transparent way to apply callbacks to either values or promises. It can do this in one of two ways:

  • Using when(value) to always create a promise
  • Passing callbacks to be applied directly to the value

Always creating a promise

By passing a single value to when() we will always create a promise. This is the most common use case and ensures that any value provided can be treated as a promise.

Here is a short example of using dojo/when to wrap a value looked up from a local cache. If the value is not cached, then a request is made to fetch the value from the server. By using when(), we normalize the output of the module to always return a promise regardless of source so that users may work with a consistent return type.

define(['dojo/request', 'dojo/when'], function(request, when) {
    var cache = {};
        
    return function (id) {
        if (id in cache) {
            return when(cache[id]);
        }
            
        return request('/value/' + id, {
            handleAs: 'json',
            method: 'POST',
        }).then(function (item) {
                return cache[id] = item;
        });
    }
});

See the full example

Passing optional callbacks

When using the optional callback arguments, dojo/when will attach the callbacks to a promise if one is supplied, but it will not create a promise when a value is passed. Instead, the callback is applied immediately and its result returned. This allows us to work with inconsistent value types in a consistent way. Often times this may happen when employing both synchronous and asynchronous strategies with third-party modules or inside the middle-layers of your application.

In the example below we use dojo/when to handle both value-based and promise-based input. If average() were to throw an exception, it would behave appropriately in both cases (i.e. by throwing the exception in calculate() or rejecting the promise in calculateRemote() ).

require(['dojo/request', 'dojo/when'], function (request, when) {
    // average() uses dojo/when so it can be used in both methods
    function average(values) {
        return when(values, function (values) {
            var total = 0;
            for(var i = 0; i < values.length; i++) {
                total += values[i];
            }
            return total / values.length;
        });
    }

    function calculate(values) {
        return average(values);
    }
    
    function calculateRemote() {
        var promise = request.post('/data/', {
            handleAs: 'json',
        });
        return promise.then(average);
    }
});

See the full example

Conclusion

Most of the time you want to use dojo/when to ensure your values can all be treated uniformly as promises. Only when a function needs to work in both synchronous and asynchronous situations and you cannot normalize the inputs would you supply the optional callback parameters.

Learning more

We cover dojo/when, promises, and async Dojo development in depth in our Dojo workshops offered throughout the US, Canada, and Europe, or at your location. We also provide expert JavaScript and Dojo support and development services, to help you get the most from efficient asynchronous JavaScript and Dojo development. Contact us to discuss how we can help.