-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Y.Deferred, yo. Let's make this happen! #241
Conversation
With some real tests, some stubbed tests. Basic functionality seems to be working, but I haven't been very rigorous about it yet.
New version uses prototypes and gentleman's privates, and is broken into two pieces: 1. `deferred` which offers Y.Deferred and Y.Promise with only deferred.then(), resolve(), reject(), promise(), and getStatus(), and promise.then() and promise(). 2. `deferred-extras` which adds deferred/promise.onProgress() and deferred.notify() for progress updates, an promise.wait() to insert a delay in the chained sequence. Also added `deferred-when` which creates a `Y.when()` method to wrap multiple operations and returns a promise that will be resolved when all individual operations complete.
Split up the code into two modules: deferred - core implementation deferred-extras - +onProgress/notify, wait, and Y.when
Plus when() now supports passing simple values as well as functions and promises. Previously, it would never resolve the allDone deferred if a simple value was passed.
Fantastic! The only thing missing is what I mention in that comment I left: a mechanism to return objects extending |
|
||
this._promise = new Y.Promise(this); | ||
|
||
this._status = 'in progress'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would a single word status be better? "progress"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe. I'm open to it, if you think it's important. To me, "progress" implies something has happened, which isn't necessarily the case. "unfulfilled" would be more appropriate, but is an odd word and would be typoed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a single word is important, and I agree that English sucks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that a single word would be best. pending?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't resist a good naming discussion. "inprogress"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
¿progresando?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"bobbingforapples"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sold! You had me at "¿".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to like pending or unfulfilled.
@lsmith This stuff looks like it will be a great API to build data-access stuff on! I'm wondering about a couple of things…
Also, I should probably do some deeper reading on the deferred/promise stuff, do you have any good links to share? |
|
* More docs in then() * errback that doesn't return a failed promise will continue to next callback, not next errback. Signals recovery from the failure. * Y.when renamed Y.batch * New Y.when(promiseOrValue, callback, errback) added * New Y.defer(callback(deferred)) added * Tests added for new APIs and changed APIs
Here's a good post about the true point of Promises: |
Yep, and it supports my want for keeping the Deferred and Promise separate. I am technically exposing the promise's underlying deferred via |
Nice article! I found a possible bug based on that article: // foo.json contains {items:[1,2,3]}
Y.io.get('foo.json')
.then(function (id, xhr) {
return JSON.parse(xhr.responseText);
})
.then(function (data) {
return data.items.map(Math.sqrt);
})
.then(function (roots) {
console.log(roots);
}, function (id, xhr) {
console.error(xhr);
}); This works ok until returning an array from the second Maybe assuming an array means an argument list is not a good idea. |
ms = Math.max(0, +ms || 0); | ||
|
||
this.then(function () { | ||
var args = slice.call(arguments); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to call slice
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is necessary to pass the then() args into the setTimeout function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean you can just do var args = arguments
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh duh! Right you are :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a couple of those around. Must.save.CPU.cycles.
Another data point, RSVP lib by Yehuda Katz and Tom Dale: |
Another implementation that ignores progress events. There's a discussion going on in the cujojs google group about propagating progress events down the promise chain. I seem to be on the "grumpy old man" side. shrug |
Update: I've been chatting with @briancavalier, who is working on better defining the Promises/A spec (yay!), and doing more research. This implementation will change, but I don't anticipate much change in the API. Look forward to more commits in the PR. |
Hey @lsmith do you think we should rewrite Domenic's test suite for YUI Test or can we run it as a CLI test? |
Now that the promises A+ spec is stable.I drafted an implementation that implements that spec following the YUI style. I'm currently writing unit tests. You can find it in a pull request in my own fork of YUI: juandopazo#4 There are some open issues:
var promise = new Y.Promise(function (fulfill, reject) {
fulfill('yay!');
});
// vs
var promise = new Y.Promise(function (resolver) {
resolver.fulfill('yay!');
}); |
Issue responses:
|
Timers: you brought it up last time we chatted about this. I'm not that concerned. I'd like to have Y.Get return promises and that would mean bundling timers and promises in end: I only ran into this when writing tests. For instance: 'some asynchronous test for promises': function () {
var test = this;
Y.when(5).then(function (value) {
// pausing and resuming work ok
test.resume();
// Assert.areEqual will throw an error which will be caught
// by then() and reject this promise instead, so Y.Test
// doesn't receive the assertion
Y.Test.Assert.areEqual(4, value, 'value should be 4');
});
test.wait();
}; I absolutely prefer not to add Syntax: I also like |
Another issue: I'm not sure Y.batch should treat functions differently. There isn't much difference between |
Hey guys, you've probably been following the resolver API convo over at Promises/A+, but just wanted to give a heads up that "fulfill" as a verb is being called into question. I'm currently against it, as are others, at least as it's been described to this point. I am strongly in favor the behavior of when.js and Q's There's a new thread on the name here |
Nevermind about tests and @briancavalier thanks for the heads-up! I agree that not being upfront with what // the identity function should work in any `then` callback
function identity(x) {
return x;
}
// for example:
Y.when(5).then(identity).then(function (value) {
console.log(value); // 5!
});
// however, if the value is a promise, it can give you an unexpected result
var promise = Y.Promise(function (fulfill) {
// promise holds a promise for 5 as a value (a promise inside a promise)
fulfill(Y.when(5));
});
// now we create a new promise going through identity
promise.then(identity).then(function (value) {
// but we get 5, not a promise, because identity returned a promise to
// then() and then() does special stuff to promises
console.log(value); // 5!
}); |
@juandopazo less magic for functions passed to @briancavalier Thanks for the heads up. I've been remiss in keeping up with the org discussions, but will catch up tomorrow (Monday). |
@juandopazo I don't quite understand what you are saying about Y.batch. Currently it accepts functions or promises as arguments, are you saying that you want it to only accept promises? If so, I'd like to argue for you to keep it the way it is. Y.batch is very similar to the API I wrote for Y.Async.runAll which I have really enjoyed using. It's true that
is not much different to
but when your code starts to include dozens of promises, something like
and if you have many such bits of code within a project, you really start to appreciate not having to repeatedly type I would even go so far as to say, you should allow |
That's what Currently Y.batch takes 3 different types of arguments: promises, functions and values. Promises and values (that are not functions) are passed through Y.when. So |
I completely looked over the call to Y.when. Okay, I see how that makes more sense, assuming you're working with other API's that return promises. Since YUI and Node.js don't currently have APIs that return promises, I'm very accustomed to using anonymous functions to wrap the async functionality everywhere. As YUI's use of promises grows, I'll be okay with Y.batch accepting promises or values. I'll always have gallery-async where I can hack in my own sugar. |
@solmsted another two points worth mentioning:
I like the convenience, but it sacrifices a reasonable use case and promotes anon-fn hackery over more maintainable styles. |
@lsmith Yes I completely agree with your 2nd point. I failed to notice the call to Y.when and never considered that simple values would be passed to Y.batch. So I'm fine with Y.batch treating functions as values. It doesn't seem necessary to add noise here but sometime in the future I'd like to resume a conversation about methods returning a promise vs anonymous callback functions. |
Closing this in favor of #445 |
Adds Y.Deferred and Y.Promise in 'deferred' module and features and Y.when (like Y.Parallel) in 'deferred-extras'.
Aimed to serve as the standard API for a transaction object/layer for big IO refactor. API feedback still welcome, though there was much discussion lsmith#36.