mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 15:40:22 +00:00
206 lines
4.6 KiB
JavaScript
206 lines
4.6 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* inspired by Kris Kowal's Q (https://github.com/kriskowal/q)
|
|
*/
|
|
|
|
/**
|
|
* Constructs a promise manager.
|
|
*
|
|
* @param {function(function)=} nextTick Function for executing functions in the next turn. Falls
|
|
* back to `setTimeout` if undefined.
|
|
* @param {function(...*)=} exceptionHandler Function into which unexpected exceptions are passed for
|
|
* debugging purposes. Falls back to `console.error` if undefined,
|
|
* @returns {object} Promise manager.
|
|
*/
|
|
function qFactory(nextTick, exceptionHandler) {
|
|
|
|
nextTick = nextTick || function(callback) {
|
|
setTimeout(callback, 0); // very rare since most of queueing will be handled within $apply
|
|
};
|
|
|
|
exceptionHandler = exceptionHandler || function(e) {
|
|
// TODO(i): console.error is somehow reset to function(a) {}, it might be a JSTD bug
|
|
if (console && console.log) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
var defer = function() {
|
|
var pending = [],
|
|
value, deferred;
|
|
|
|
deferred = {
|
|
|
|
resolve: function(val) {
|
|
if (pending) {
|
|
var callbacks = pending;
|
|
pending = undefined;
|
|
value = ref(val);
|
|
|
|
if (callbacks.length) {
|
|
nextTick(function() {
|
|
var callback;
|
|
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
|
callback = callbacks[i];
|
|
value.then(callback[0], callback[1]);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
reject: function(reason) {
|
|
deferred.resolve(reject(reason));
|
|
},
|
|
|
|
|
|
promise: {
|
|
then: function(callback, errback) {
|
|
var result = defer();
|
|
|
|
var wrappedCallback = function(value) {
|
|
try {
|
|
result.resolve((callback || defaultCallback)(value));
|
|
} catch(e) {
|
|
exceptionHandler(e);
|
|
result.reject(e);
|
|
}
|
|
};
|
|
|
|
var wrappedErrback = function(reason) {
|
|
try {
|
|
result.resolve((errback || defaultErrback)(reason));
|
|
} catch(e) {
|
|
exceptionHandler(e);
|
|
result.reject(e);
|
|
}
|
|
};
|
|
|
|
if (pending) {
|
|
pending.push([wrappedCallback, wrappedErrback]);
|
|
} else {
|
|
value.then(wrappedCallback, wrappedErrback);
|
|
}
|
|
|
|
return result.promise;
|
|
}
|
|
}
|
|
};
|
|
|
|
return deferred;
|
|
};
|
|
|
|
|
|
var ref = function(value) {
|
|
if (value && value.then) return value;
|
|
return {
|
|
then: function(callback) {
|
|
var result = defer();
|
|
nextTick(function() {
|
|
result.resolve(callback(value));
|
|
});
|
|
return result.promise;
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
var reject = function(reason) {
|
|
return {
|
|
then: function(callback, errback) {
|
|
var result = defer();
|
|
nextTick(function() {
|
|
result.resolve(errback(reason));
|
|
});
|
|
return result.promise;
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
var when = function(value, callback, errback) {
|
|
var result = defer(),
|
|
done;
|
|
|
|
var wrappedCallback = function(value) {
|
|
try {
|
|
return (callback || defaultCallback)(value);
|
|
} catch (e) {
|
|
exceptionHandler(e);
|
|
return reject(e);
|
|
}
|
|
};
|
|
|
|
var wrappedErrback = function(reason) {
|
|
try {
|
|
return (errback || defaultErrback)(reason);
|
|
} catch (e) {
|
|
exceptionHandler(e);
|
|
return reject(e);
|
|
}
|
|
};
|
|
|
|
nextTick(function() {
|
|
ref(value).then(function(value) {
|
|
if (done) return;
|
|
done = true;
|
|
result.resolve(ref(value).then(wrappedCallback, wrappedErrback));
|
|
}, function(reason) {
|
|
if (done) return;
|
|
done = true;
|
|
result.resolve(wrappedErrback(reason));
|
|
});
|
|
});
|
|
|
|
return result.promise;
|
|
};
|
|
|
|
|
|
function defaultCallback(value) {
|
|
return value;
|
|
}
|
|
|
|
|
|
function defaultErrback(reason) {
|
|
return reject(reason);
|
|
}
|
|
|
|
|
|
function all(promises) {
|
|
var deferred = defer(),
|
|
counter = promises.length,
|
|
results = [];
|
|
|
|
forEach(promises, function(promise, index) {
|
|
promise.then(function(value) {
|
|
if (index in results) return;
|
|
results[index] = value;
|
|
if (!(--counter)) deferred.resolve(results);
|
|
}, function(reason) {
|
|
if (index in results) return;
|
|
deferred.reject(reason);
|
|
});
|
|
});
|
|
|
|
return deferred.promise;
|
|
}
|
|
|
|
return {
|
|
defer: defer,
|
|
reject: reject,
|
|
when: when,
|
|
all: all
|
|
};
|
|
}
|
|
|
|
// TODO(i): move elsewhere
|
|
function $QProvider() {
|
|
|
|
this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
|
|
return qFactory(function(callback) {
|
|
$rootScope.$evalAsync(callback);
|
|
}, $exceptionHandler);
|
|
}];
|
|
}
|