diff --git a/src/ng/q.js b/src/ng/q.js index b4568c607427..3df34cc5ef01 100644 --- a/src/ng/q.js +++ b/src/ng/q.js @@ -299,14 +299,18 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { * @returns {Deferred} Returns a new instance of deferred. */ function defer() { - var d = new Deferred(); - //Necessary to support unbound execution :/ - d.resolve = simpleBind(d, d.resolve); - d.reject = simpleBind(d, d.reject); - d.notify = simpleBind(d, d.notify); - return d; + return new Deferred(); } + function Deferred() { + var promise = this.promise = new Promise(); + //Non prototype methods necessary to support unbound execution :/ + this.resolve = function(val) { resolvePromise(promise, val); }; + this.reject = function(reason) { rejectPromise(promise, reason); }; + this.notify = function(progress) { notifyPromise(promise, progress); }; + } + + function Promise() { this.$$state = { status: 0 }; } @@ -316,13 +320,13 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) { return this; } - var result = new Deferred(); + var result = new Promise(); this.$$state.pending = this.$$state.pending || []; this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]); if (this.$$state.status > 0) scheduleProcessQueue(this.$$state); - return result.promise; + return result; }, 'catch': function(callback) { @@ -338,15 +342,8 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } }); - //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native - function simpleBind(context, fn) { - return function(value) { - fn.call(context, value); - }; - } - function processQueue(state) { - var fn, deferred, pending; + var fn, promise, pending; pending = state.pending; state.processScheduled = false; @@ -354,18 +351,18 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { try { for (var i = 0, ii = pending.length; i < ii; ++i) { state.pur = true; - deferred = pending[i][0]; + promise = pending[i][0]; fn = pending[i][state.status]; try { if (isFunction(fn)) { - deferred.resolve(fn(state.value)); + resolvePromise(promise, fn(state.value)); } else if (state.status === 1) { - deferred.resolve(state.value); + resolvePromise(promise, state.value); } else { - deferred.reject(state.value); + rejectPromise(promise, state.value); } } catch (e) { - deferred.reject(e); + rejectPromise(promise, e); } } } finally { @@ -401,83 +398,80 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { nextTick(function() { processQueue(state); }); } - function Deferred() { - this.promise = new Promise(); + function resolvePromise(promise, val) { + if (promise.$$state.status) return; + if (val === promise) { + $$reject(promise, $qMinErr( + 'qcycle', + 'Expected promise to be resolved with value other than itself \'{0}\'', + val)); + } else { + $$resolve(promise, val); + } + } - extend(Deferred.prototype, { - resolve: function(val) { - if (this.promise.$$state.status) return; - if (val === this.promise) { - this.$$reject($qMinErr( - 'qcycle', - 'Expected promise to be resolved with value other than itself \'{0}\'', - val)); + function $$resolve(promise, val) { + var then; + var done = false; + try { + if ((isObject(val) || isFunction(val))) then = val && val.then; + if (isFunction(then)) { + promise.$$state.status = -1; + then.call(val, doResolve, doReject, doNotify); } else { - this.$$resolve(val); - } - }, - - $$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, simpleBind(this, this.notify)); - } else { - this.promise.$$state.value = val; - this.promise.$$state.status = 1; - scheduleProcessQueue(this.promise.$$state); - } - } catch (e) { - rejectPromise(e); + promise.$$state.value = val; + promise.$$state.status = 1; + scheduleProcessQueue(promise.$$state); } + } catch (e) { + doReject(e); + } - function resolvePromise(val) { - if (done) return; - done = true; - that.$$resolve(val); - } - function rejectPromise(val) { - if (done) return; - done = true; - that.$$reject(val); - } - }, + function doResolve(val) { + if (done) return; + done = true; + $$resolve(promise, val); + } + function doReject(val) { + if (done) return; + done = true; + $$reject(promise, val); + } + function doNotify(progress) { + notifyPromise(promise, progress); + } + } - reject: function(reason) { - if (this.promise.$$state.status) return; - this.$$reject(reason); - }, + function rejectPromise(promise, reason) { + if (promise.$$state.status) return; + $$reject(promise, reason); + } - $$reject: function(reason) { - this.promise.$$state.value = reason; - this.promise.$$state.status = 2; - scheduleProcessQueue(this.promise.$$state); - }, + function $$reject(promise, reason) { + promise.$$state.value = reason; + promise.$$state.status = 2; + scheduleProcessQueue(promise.$$state); + } - notify: function(progress) { - var callbacks = this.promise.$$state.pending; - - if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) { - nextTick(function() { - var callback, result; - for (var i = 0, ii = callbacks.length; i < ii; i++) { - result = callbacks[i][0]; - callback = callbacks[i][3]; - try { - result.notify(isFunction(callback) ? callback(progress) : progress); - } catch (e) { - exceptionHandler(e); - } + function notifyPromise(promise, progress) { + var callbacks = promise.$$state.pending; + + if ((promise.$$state.status <= 0) && callbacks && callbacks.length) { + nextTick(function() { + var callback, result; + for (var i = 0, ii = callbacks.length; i < ii; i++) { + result = callbacks[i][0]; + callback = callbacks[i][3]; + try { + notifyPromise(result, isFunction(callback) ? callback(progress) : progress); + } catch (e) { + exceptionHandler(e); } - }); - } + } + }); } - }); + } /** * @ngdoc method @@ -516,9 +510,9 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. */ function reject(reason) { - var result = new Deferred(); - result.reject(reason); - return result.promise; + var result = new Promise(); + rejectPromise(result, reason); + return result; } function handleCallback(value, resolver, callback) { @@ -556,9 +550,9 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { function when(value, callback, errback, progressBack) { - var result = new Deferred(); - result.resolve(value); - return result.promise.then(callback, errback, progressBack); + var result = new Promise(); + resolvePromise(result, value); + return result.then(callback, errback, progressBack); } /** @@ -594,7 +588,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { */ function all(promises) { - var deferred = new Deferred(), + var result = new Promise(), counter = 0, results = isArray(promises) ? [] : {}; @@ -602,17 +596,17 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { counter++; when(promise).then(function(value) { results[key] = value; - if (!(--counter)) deferred.resolve(results); + if (!(--counter)) resolvePromise(result, results); }, function(reason) { - deferred.reject(reason); + rejectPromise(result, reason); }); }); if (counter === 0) { - deferred.resolve(results); + resolvePromise(result, results); } - return deferred.promise; + return result; } /** @@ -644,19 +638,19 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver); } - var deferred = new Deferred(); + var promise = new Promise(); function resolveFn(value) { - deferred.resolve(value); + resolvePromise(promise, value); } function rejectFn(reason) { - deferred.reject(reason); + rejectPromise(promise, reason); } resolver(resolveFn, rejectFn); - return deferred.promise; + return promise; } // Let's make the instanceof operator work for promises, so that