-
Notifications
You must be signed in to change notification settings - Fork 27.4k
Conversation
|
||
fns = callOnce(this, this.$$resolve, this.$$reject); | ||
if (isPromiseLike(val)) { |
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.
in theory, this looks fine, but I think this will break Promise/A+
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.
Previously it was (isObject(val) || isFunction(val)) && val && isFunction(val.then)
. Now it is val && isFunction(val.then)
. Is the first one more correct then the second?
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.
before val.then
was only retrieved once. This changed
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.
also, true.then
(if defined), must not be handled as a promise (same with numeric values)
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'll have to look into the Promise/A+ tests. It looks like the isObject(val) || isFunction(val)
is important...
Clearly I need to look into the aplus tests more (which I'm having trouble running on windows). The second commit could be done on it's own with a few minor changes though. |
I think it's fixed now. The |
There are two parts in this PR, the changes on |
Personally I thought the Here's the Here's a chart showing master, +simpleBind, +simpleBind +callOnce. This would be kb after performing the op 50x. Note that normally the retained memory is the same except when the test didn't resolve a promise so the deferred is still alive - then the difference might be in the retained memory more then GCed memory.
|
@jbedard what about $$resolve: function(val) {
var then;
var that = this;
var done = false;
try {
if (isObject(val) || isFunction(val)) then = val.then;
if (isFunction(then)) {
this.promise.$$state.status = -1;
then.call(val, resolvePromise, rejectPromise, notify);
} else {
this.promise.$$state.value = val;
this.promise.$$state.status = 1;
scheduleProcessQueue(this.promise.$$state);
}
} catch (e) {
rejectPromise(e);
exceptionHandler(e);
}
function resolvePromise(val) {
if (done) return;
done = true;
that.$$resolve(val);
}
function rejectPromise(val) {
if (done) return;
done = true;
that.$$reject(val);
}
function notify(progress) { that.notify(progress); }
} ? |
I think that will still create 3 closures every time I think your snippet is more readable then |
@lgalfaso I've added your |
@jbedard Promise/A+ is very strict on the implementation, and having an implementation that is a direct mapping from the spec is a big plus. If this implies that 3 new closures happen for every promise resolution, I still think it is best. As a side not, the closure on |
I don't think what I'm proposing deviates from the spec, it just pushes some work one function call deeper so it doesn't occur unless necessary. Does the spec somehow dictate how many internal function calls you can make? |
it does not dictate anything about how many functions deep it should go, but the current implementation is a perfect mapping on each check that should be done and the order that they should be performed. If a future clarification/revision is made (as it happened before), having this mapping helps a lot |
I think this PR improves that. This separates 3.i - 3.iv, 4 into separate logical blocks (which could be functions) where currently they are all mixed together and do not map to the spec well. I find it quite confusing today where fetching |
it looks like we will have to disagree, I still find the new code at |
Do you think it's worth removing these closures at all? I can think of many other ways of doing it... For example your snippet but with the resolve/notify inlined removes 2/3 closures (but the reject can not be inlined because it is also used in the I've swapped the order of the commits in this PR so the |
The |
- changes Deferred.$$resolve to only wrap the internal resolve/reject when wrapping another promise
Updated... |
- changes Deferred.$$resolve to only wrap the internal resolve/reject when wrapping another promise Closes: angular#13293
First commit:
$$reject
/$$resolve
when necessary, which is when a promise is resolved with another promise as the result. This is now in a$$delayResolve
method.$$reject
/$$resolve
methods, it already existed innotify
UseisPromiseLike
instead of redefining it, this is a slight functional change since they were differentSecond:
Deferred
methods when theDeferred
will be returned publicly ($q.defer
). Most of the time it is only used internally and the binding isn't necessary. The other option is to stop binding them completely which would be nicer but would be a breaking change.All the
Deferred
/Promise
methods use somewhere between 20-80% less memory except for a few with no changes ($q.defer()
,promise.then()
(no args))...