Preparing for when.js 2.0.0

98 views
Skip to first unread message

Brian Cavalier

unread,
Feb 26, 2013, 2:03:41 PM2/26/13
to
Version 2.0.0 of when.js will be released soon.  There are a couple of simple things that you need to be aware of as you get ready.

In preparation for 2.0.0, you can test your code against the dev-200 branch.  If you have any questions about the upcoming 2.0.0 release, please feel free to post questions here!

Deprecated APIs

There are a handful of deprecated APIs that will be removed or renamed in 2.0.0.  Here is the full list of current deprecations, with their new 2.0.0 alternatives.  You will need to update your code accordingly.  If you use when/debug in 1.8.1, it will log obnoxious warnings about these to the console.

* removed deferred.then - use deferred.promise.then
* renamed deferred.progress - use deferred.notify
* renamed deferred.resolver.progress - use deferred.resolver.notify
* removed when.chain - see here for alternatives and the reasons for deprecating
* removed when/timed - this module only aggregated two other existing modules and provided no additional functionality. Use when/timeout and/or when/delay directly

Asynchronous Resolutions

In versions prior to 2.0.0, when.js allowed promise callbacks to be invoked immediately for a promise that was already fulfilled or rejected.  The problem this creates is one of inconsistency.  Under some conditions, promise callbacks would be called immediately, and under other conditions, they would be called asynchronously (e.g. in a future event loop turn).  Consider the following code:

function doStuff(promise) {
 
var i = 0;
  promise
.then(function() {
    console
.log(i);
 
});

  i
++;
}

Admittedly, this is an extremely trivial example, but it illustrates the point.  This function accepts a promise, which might still be pending, or might be already fulfilled.  The function itself cannot know the state of the promise, and will behave differently depending on whether the promise is already-fulfilled (doStuff will log 0 immediately) or pending (doStuff will log 1 after promise is fulfilled).  One implication of this is that the developer must write unit tests for both the pending and fulfilled cases (and possibly the rejected case as well), and not doing so could lead to errors in production.  As you can imagine, with more complex functions in complex software systems, this kind of unpredictability can be very difficult to track down if/when it causes a problem.

In when.js 2.0.0, promise callbacks will never be called immediately.  They will always be called asynchronously.  This means that the doStuff function above will log 1 regardless of whether promise is already fulfilled or is still pending at the time doStuff executes--it simply cannot log 0.  By guaranteeing consistency, we feel when.js reduces possible mistakes and eases the testing burden.


Brian Cavalier

unread,
Mar 6, 2013, 12:28:15 PM3/6/13
to cuj...@googlegroups.com
We recently merged the dev-200 branch to the dev branch.  So, please test with dev (even though the code hasn't really changed much from dev-200, and probably won't).

2.0 is imminent!

Brian Cavalier

unread,
Mar 7, 2013, 12:55:48 PM3/7/13
to cuj...@googlegroups.com
REMINDER: deferred.then is deprecated, and WILL NOT EXIST in 2.0.  It has been removed from the dev branch.

To help you track down any leftover calls to deferred.then, we created this branch.  Load when/debug instead of when, and any calls to deferred.then will throw an uncatchable exception with a stack trace pointing to the spot where the deferred was created.  We'll likely keep this in the 2.0 release if it proves to be useful, and then remove it in a later release, such as 2.1.

thanpolas

unread,
Mar 25, 2013, 10:37:55 AM3/25/13
to cuj...@googlegroups.com
There is an equal argument for synchronous resolution to be made here for cases where synchronous invocation was the expected behavior...

I guess now it's too late to raise it

Brian Cavalier

unread,
Mar 25, 2013, 12:22:47 PM3/25/13
to cuj...@googlegroups.com
This has been discussed at length by many promise implementors and by the Promises/A+ group.  Ultimately, promises are a tool for managing asynchrony, so assuming they will be synchronous is dangerous.

The problem is that since Javascript has no blocking `wait` facility, there simply is no way to *guarantee* synchronous resolutions, rather they can only be *allowed*.  When multiple promise implementations are in play (and there are many, e.g. when.js, Q, Dojo, jQuery, etc etc etc and more to come ... YUI, for example, is getting promises), the only safe thing to do is to force asynchrony in all cases.  For example, it is impossible for jQuery's $.when() to somehow cause a when.js 2.0 promise to "become" synchronous.

In addition, the only safe assumption for a promise consumer is asynchrony.  Even if synchronous resolutions are allowed, a promise consumer cannot tell (and *should not* be able to tell) whether a promise is already settled (fulfilled or rejected) or still pending.  Given those things, if sync resolutions are allowed, then any promise to which you might be given a reference *may* resolve synchronously, or *may* resolve asynchronous, thereby opening the door to the hazards mentioned in the original post.

I agree that careful programmers who own all of the code in their application can avoid the hazards.  However, in a team with a range of skill levels and experience and in applications with a mix in plenty of 3rd party code, the hazards can be costly.

Like all things, it's a tradeoff.  We feel like the consistency of async is a net win.  

thanpolas

unread,
Mar 25, 2013, 12:24:54 PM3/25/13
to cuj...@googlegroups.com
that makes perfect sense, 

thank you Brian for the thorough explanation

Brian Cavalier

unread,
Mar 25, 2013, 1:31:17 PM3/25/13
to cuj...@googlegroups.com
Anytime!
Reply all
Reply to author
Forward
0 new messages