Dojo FAQ: Why don’t object stores always return a promise?

By on August 27, 2013 12:27 pm

When getting started with Dojo’s store API, it is important to realize that not all stores are created equal. Some stores, such as the JsonRest store, communicate with a server for every request, and each of their methods return a promise resolving when the asynchronous request completes. Others, such as the Memory store, can perform their logic synchronously, so their methods return immediate values.

This variance in the nature of store method return values can present a challenge when trying to write code that can work with any type of store. Fortunately, Dojo has tools to help in precisely this situation.

For example, let’s start with an asynchronous JsonRest store:

require([
	'dojo/store/JsonRest'
], function (JsonRest) {
	var store = new JsonRest({ target: '/data/' });

	store.get('1').then(function (item) {
		// do something with the object whose "id" is "1"
	});
});

This will work fine — a JsonRest store issues a server request for each call to get, so it will always return a promise, resolving asynchronously.

Later, you decide to implement some client-side caching for your JsonRest store using the Cache module:

require([
	'dojo/store/JsonRest',
	'dojo/store/Memory',
	'dojo/store/Cache'
], function (JsonRest, Memory, Cache) {
	var restStore = new JsonRest({ target: '/data/' });
	var memoryStore = new Memory();
	var store = new Cache(restStore, memoryStore);

	store.get('1').then(function (item) {
		// do something with the object whose "id" is "1"
	});
});

At first, it seems to work, but then you start to see errors (“Object has no method ‘then'” or “then is not defined”)! What’s happening is the initial queries are made asynchronously, but the results get cached, so subsequent queries hit the cache and are returned immediately (synchronously). Store methods may return a promise or a value.

Sync or async? Use dojo/when

Fortunately, Dojo includes a function designed to make handling synchronous and asynchronous values in a simple and consistent manner: dojo/when. Updating the above code is simple:

require([
	'dojo/store/JsonRest',
	'dojo/store/Memory',
	'dojo/store/Cache',
	'dojo/when'
], function (JsonRest, Memory, Cache, when) {
	var restStore = new JsonRest({ target: '/data/' });
	var memoryStore = new Memory();
	var store = new Cache(restStore, memoryStore);

	when(store.get('1')).then(function (item) {
		// do something with the object whose "id" is "1"
	});
});

This code will handle the store’s return value appropriately whether it’s a promise or an immediate value. When the when function is called with a single argument, it will always return a promise, regardless as to whether the argument passed was a promise. We can then use the then method to act on that promise as usual.

In Closing

It can be tricky learning to work with sometimes-asynchronous APIs, but once you understand the fundamentals, you’ll appreciate the convenience modules Dojo provides that enable you to write clear, well-organized, and consistent code.