- // Check for Promise.all as Chrome 30 shipped an implementation
- // without it and with some other quirks and we don't want to use
- // that one.
- if (typeof Promise === "undefined" || !Promise.all) (function () {
- /* Polyfill based heavily on Christoph Burgmer's ayepromise
-
- https://github.com/cburgmer/ayepromise/blob/master/ayepromise.js
- */
- /* Wrap an arbitrary number of functions and allow only one of
- them to be executed and only once */
- function once () {
- var wasCalled = false;
-
- return function (wrappedFunction) {
- return function () {
- if (wasCalled) {
- return;
- }
- wasCalled = true;
- wrappedFunction.apply(null, arguments);
- };
- };
- }
-
- function getThenableIfExists (obj) {
- // Make sure we only access the accessor once as required by the spec
- var then = obj && obj.then;
-
- if (typeof obj === "object" && typeof then === "function")
- return then.bind(obj);
- }
-
- function aThenHandler (onFulfilled, onRejected) {
- var deferred = defer();
-
- function doHandlerCall (func, value) {
- setTimeout(function () {
- var returnValue;
- try {
- returnValue = func(value);
- } catch (e) {
- deferred.reject(e);
- return;
- }
-
- if (returnValue === deferred.promise) {
- deferred.reject(new TypeError());
- } else {
- deferred.resolve(returnValue);
- }
- }, 0);
- }
-
- return {
- promise: deferred.promise,
- callFulfilled: function (value) {
- if (onFulfilled && onFulfilled.call) {
- doHandlerCall(onFulfilled, value);
- } else {
- deferred.resolve(value);
- }
- },
- callRejected: function (value) {
- if (onRejected && onRejected.call) {
- doHandlerCall(onRejected, value);
- } else {
- deferred.reject(value);
- }
- }
- };
- }
-
- function defer () {
- // States
- var PENDING = 0,
- FULFILLED = 1,
- REJECTED = 2;
-
- var state = PENDING,
- outcome,
- thenHandlers = [];
-
- function doFulfill (value) {
- state = FULFILLED;
- outcome = value;
-
- thenHandlers.forEach(function (then) {
- then.callFulfilled(outcome);
- });
- thenHandlers = null;
- }
-
- function doReject (error) {
- state = REJECTED;
- outcome = error;
-
- thenHandlers.forEach(function (then) {
- then.callRejected(outcome);
- });
- thenHandlers = null;
- }
-
- function registerThenHandler (onFulfilled, onRejected) {
- var thenHandler = aThenHandler(onFulfilled, onRejected);
-
- if (state === FULFILLED) {
- thenHandler.callFulfilled(outcome);
- } else if (state === REJECTED) {
- thenHandler.callRejected(outcome);
- } else {
- thenHandlers.push(thenHandler);
- }
-
- return thenHandler.promise;
- }
-
- function safelyResolveThenable (thenable) {
- // Either fulfill, reject or reject with error
- var onceWrapper = once();
- try {
- thenable(
- onceWrapper(transparentlyResolveThenablesAndFulfill),
- onceWrapper(doReject)
- );
- } catch (e) {
- onceWrapper(doReject)(e);
- }
- }
-
- function transparentlyResolveThenablesAndFulfill (value) {
- var thenable;
-
- try {
- thenable = getThenableIfExists(value);
- } catch (e) {
- doReject(e);
- return;
- }
-
- if (thenable) {
- safelyResolveThenable(thenable);
- } else {
- doFulfill(value);
- }
- }
-
- var onceWrapper = once();
- return {
- resolve: onceWrapper(transparentlyResolveThenablesAndFulfill),
- reject: onceWrapper(doReject),
- promise: {
- then: registerThenHandler,
- "catch": function (onRejected) {
- return registerThenHandler(null, onRejected);
- }
- }
- };
- }
-
- function Promise (callback) {
- var deferred = defer();
- try {
- callback(deferred.resolve, deferred.reject);
- } catch (exc) {
- deferred.reject(exc);
- }
- return deferred.promise;
- }
-
- Promise.resolve = function (v) {
- return new Promise(function (resolve) { resolve(v); });
- };
-
- Promise.reject = function (error) {
- return new Promise(function (_, reject) { reject(error); });
- };
-
- Promise.all = function (promises) {
- return new Promise(function (resolve, reject) {
- var results = [];
- var remaining = promises.length;
- if (remaining === 0)
- return resolve([]);
-
- promises.forEach(function (promise, i) {
- var then = getThenableIfExists(promise);
- function resolve1 (value) {
- results[i] = value;
- if (--remaining === 0)
- resolve(results);
- }
- if (then) {
- then.call(promise, resolve1, reject);
- } else {
- --remaining;
- results[i] = promise;
- }
- });
- });
- };
-
- this.Promise = Promise;
- }).call(this);