Skip to content

Instantly share code, notes, and snippets.

@briancavalier
Created March 15, 2011 13:46
Show Gist options
  • Save briancavalier/870729 to your computer and use it in GitHub Desktop.
Save briancavalier/870729 to your computer and use it in GitHub Desktop.
A better, imho, when() function that normalizes its return value to a promise
// An alternative to dojo.when that always returns a promise
// The problem with dojo.when, imho, is that you have no idea
// what it will return, so if you want to chain anything, you
// end up with lots of nested when()s, like this:
// dojo.when(dojo.when(dojo.when(thing)))
//
// This alternative always returns a promise, so you can write:
// when(thing).then().then().then()
// which is much more intuitive, imho.
//
// Note that Promise is probably dojo._base.Deferred if you're
// using dojo.
//
// promised-io has a similar function named whenPromise(),
// so if you use this you may want to adopt its naming convention.
// See: https://github.com/kriszyp/promised-io/blob/master/lib/promise.js
function when(valueOrPromise) {
var promise;
if(isPromise(valueOrPromise)) {
promise = valueOrPromise;
} else {
promise = new Promise();
promise.resolve(valueOrPromise);
}
return promise;
}
// An example implementation of isPromise()
function isPromise(valueOrPromise) {
return valueOrPromise && typeof valueOrPromise.then == 'function';
}
@briancavalier
Copy link
Author

@tobie That is an interesting example, for sure. However, I think the "unpredictable" outcome seems more due to invalid assumptions, rather than any inherent problem with promises or my implementation of when() (or dojo's implementation, in fact). I think it is making two invalid assumptions: 1) that the two promises will resolve in the same order every time, and 2) the first promise will always resolve before the value of template is changed. Neither of those, imho is valid for an async programming model.

So, I think deferring with setTimeout may not be necessary. I'd advocate refactoring code like that to remove the assumptions. What do you think? As always, it's entirely possible that I've missed something subtle (or not so subtle!) about your example, so please let me know if I did!

Re: duck-typed promises. Yes, you are absolutely right that CommonJS says they must be feature-testable. In fact, Kris Zyp's CommonJS Promises/A proposal says specifically: "A promise is defined as an object that has a function as the value for the property 'then'" (here: http://wiki.commonjs.org/wiki/Promises/A). Wrapping that test up in a function, in some sense, just saves some typing, and will probably minify better in most compressors. However, if the method for determining whether something is a promise should ever change, it would also help with maintenance, as @unscriptable and @cjohansen hinted at.

The problem I kept running into was having to feature test the return value of dojo.when() which was tedious, or having to nest dojo.when(), which, to my eyes, is harder to read than when().then().then(). That's personal preference, of course.

@tobie
Copy link

tobie commented Mar 15, 2011

Better explanation that I could give.

Contrary to popular belief, sync programming is not a subset of async programming. The two should be considered mutually exclusive.

For example, you would have no way to collect the first chunk of data from the following stream if it somehow was cached and emitted synchronously.:

var stream = new Stream();
stream.on('data', doStuff);

@cjohansen
Copy link

"Contrary to popular belief, sync programming is not a subset of async programming. The two should be considered mutually exclusive."

Well said @tobie! :)

As for duck-typed promises, I'm aware of Kris Zyp's proposal and it's wording. I still think isPromise will make the code both easier to understand, and possibly easier to maintain in the long run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment