372 lines
9.0 KiB
JavaScript
372 lines
9.0 KiB
JavaScript
/**
|
||
* setImmediate polyfill v1.0.1, supports IE9+
|
||
* © 2014–2015 Dmitry Korobkin
|
||
* Released under the MIT license
|
||
* github.com/Octane/setImmediate
|
||
*/
|
||
window.setImmediate || function () {'use strict';
|
||
|
||
var uid = 0;
|
||
var storage = {};
|
||
var firstCall = true;
|
||
var slice = Array.prototype.slice;
|
||
var message = 'setImmediatePolyfillMessage';
|
||
|
||
function fastApply(args) {
|
||
var func = args[0];
|
||
switch (args.length) {
|
||
case 1:
|
||
return func();
|
||
case 2:
|
||
return func(args[1]);
|
||
case 3:
|
||
return func(args[1], args[2]);
|
||
}
|
||
return func.apply(window, slice.call(args, 1));
|
||
}
|
||
|
||
function callback(event) {
|
||
var key = event.data;
|
||
var data;
|
||
if (typeof key == 'string' && key.indexOf(message) == 0) {
|
||
data = storage[key];
|
||
if (data) {
|
||
delete storage[key];
|
||
fastApply(data);
|
||
}
|
||
}
|
||
}
|
||
|
||
window.setImmediate = function setImmediate() {
|
||
var id = uid++;
|
||
var key = message + id;
|
||
var i = arguments.length;
|
||
var args = new Array(i);
|
||
while (i--) {
|
||
args[i] = arguments[i];
|
||
}
|
||
storage[key] = args;
|
||
if (firstCall) {
|
||
firstCall = false;
|
||
window.addEventListener('message', callback);
|
||
}
|
||
window.postMessage(key, '*');
|
||
return id;
|
||
};
|
||
|
||
window.clearImmediate = function clearImmediate(id) {
|
||
delete storage[message + id];
|
||
};
|
||
|
||
}();
|
||
|
||
/**
|
||
* Promise polyfill v1.0.10
|
||
* requires setImmediate
|
||
*
|
||
* © 2014–2015 Dmitry Korobkin
|
||
* Released under the MIT license
|
||
* github.com/Octane/Promise
|
||
*/
|
||
(function (global) {'use strict';
|
||
|
||
var STATUS = '[[PromiseStatus]]';
|
||
var VALUE = '[[PromiseValue]]';
|
||
var ON_FUlFILLED = '[[OnFulfilled]]';
|
||
var ON_REJECTED = '[[OnRejected]]';
|
||
var ORIGINAL_ERROR = '[[OriginalError]]';
|
||
var PENDING = 'pending';
|
||
var INTERNAL_PENDING = 'internal pending';
|
||
var FULFILLED = 'fulfilled';
|
||
var REJECTED = 'rejected';
|
||
var NOT_ARRAY = 'not an array.';
|
||
var REQUIRES_NEW = 'constructor Promise requires "new".';
|
||
var CHAINING_CYCLE = 'then() cannot return same Promise that it resolves.';
|
||
|
||
var setImmediate = global.setImmediate || require('timers').setImmediate;
|
||
var isArray = Array.isArray || function (anything) {
|
||
return Object.prototype.toString.call(anything) == '[object Array]';
|
||
};
|
||
|
||
function InternalError(originalError) {
|
||
this[ORIGINAL_ERROR] = originalError;
|
||
}
|
||
|
||
function isInternalError(anything) {
|
||
return anything instanceof InternalError;
|
||
}
|
||
|
||
function isObject(anything) {
|
||
//Object.create(null) instanceof Object → false
|
||
return Object(anything) === anything;
|
||
}
|
||
|
||
function isCallable(anything) {
|
||
return typeof anything == 'function';
|
||
}
|
||
|
||
function isPromise(anything) {
|
||
return anything instanceof Promise;
|
||
}
|
||
|
||
function identity(value) {
|
||
return value;
|
||
}
|
||
|
||
function thrower(reason) {
|
||
throw reason;
|
||
}
|
||
|
||
function enqueue(promise, onFulfilled, onRejected) {
|
||
if (!promise[ON_FUlFILLED]) {
|
||
promise[ON_FUlFILLED] = [];
|
||
promise[ON_REJECTED] = [];
|
||
}
|
||
promise[ON_FUlFILLED].push(onFulfilled);
|
||
promise[ON_REJECTED].push(onRejected);
|
||
}
|
||
|
||
function clearAllQueues(promise) {
|
||
delete promise[ON_FUlFILLED];
|
||
delete promise[ON_REJECTED];
|
||
}
|
||
|
||
function callEach(queue) {
|
||
var i;
|
||
var length = queue.length;
|
||
for (i = 0; i < length; i++) {
|
||
queue[i]();
|
||
}
|
||
}
|
||
|
||
function call(resolve, reject, value) {
|
||
var anything = toPromise(value);
|
||
if (isPromise(anything)) {
|
||
anything.then(resolve, reject);
|
||
} else if (isInternalError(anything)) {
|
||
reject(anything[ORIGINAL_ERROR]);
|
||
} else {
|
||
resolve(value);
|
||
}
|
||
}
|
||
|
||
function toPromise(anything) {
|
||
var then;
|
||
if (isPromise(anything)) {
|
||
return anything;
|
||
}
|
||
if(isObject(anything)) {
|
||
try {
|
||
then = anything.then;
|
||
} catch (error) {
|
||
return new InternalError(error);
|
||
}
|
||
if (isCallable(then)) {
|
||
return new Promise(function (resolve, reject) {
|
||
setImmediate(function () {
|
||
try {
|
||
then.call(anything, resolve, reject);
|
||
} catch (error) {
|
||
reject(error);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function resolvePromise(promise, resolver) {
|
||
function resolve(value) {
|
||
if (promise[STATUS] == PENDING) {
|
||
fulfillPromise(promise, value);
|
||
}
|
||
}
|
||
function reject(reason) {
|
||
if (promise[STATUS] == PENDING) {
|
||
rejectPromise(promise, reason);
|
||
}
|
||
}
|
||
try {
|
||
resolver(resolve, reject);
|
||
} catch(error) {
|
||
reject(error);
|
||
}
|
||
}
|
||
|
||
function fulfillPromise(promise, value) {
|
||
var queue;
|
||
var anything = toPromise(value);
|
||
if (isPromise(anything)) {
|
||
promise[STATUS] = INTERNAL_PENDING;
|
||
anything.then(
|
||
function (value) {
|
||
fulfillPromise(promise, value);
|
||
},
|
||
function (reason) {
|
||
rejectPromise(promise, reason);
|
||
}
|
||
);
|
||
} else if (isInternalError(anything)) {
|
||
rejectPromise(promise, anything[ORIGINAL_ERROR]);
|
||
} else {
|
||
promise[STATUS] = FULFILLED;
|
||
promise[VALUE] = value;
|
||
queue = promise[ON_FUlFILLED];
|
||
if (queue && queue.length) {
|
||
clearAllQueues(promise);
|
||
callEach(queue);
|
||
}
|
||
}
|
||
}
|
||
|
||
function rejectPromise(promise, reason) {
|
||
var queue = promise[ON_REJECTED];
|
||
promise[STATUS] = REJECTED;
|
||
promise[VALUE] = reason;
|
||
if (queue && queue.length) {
|
||
clearAllQueues(promise);
|
||
callEach(queue);
|
||
}
|
||
}
|
||
|
||
function Promise(resolver) {
|
||
var promise = this;
|
||
if (!isPromise(promise)) {
|
||
throw new TypeError(REQUIRES_NEW);
|
||
}
|
||
promise[STATUS] = PENDING;
|
||
promise[VALUE] = undefined;
|
||
resolvePromise(promise, resolver);
|
||
}
|
||
|
||
Promise.prototype.then = function (onFulfilled, onRejected) {
|
||
var promise = this;
|
||
var nextPromise;
|
||
onFulfilled = isCallable(onFulfilled) ? onFulfilled : identity;
|
||
onRejected = isCallable(onRejected) ? onRejected : thrower;
|
||
nextPromise = new Promise(function (resolve, reject) {
|
||
function tryCall(func) {
|
||
var value;
|
||
try {
|
||
value = func(promise[VALUE]);
|
||
} catch (error) {
|
||
reject(error);
|
||
return;
|
||
}
|
||
if (value === nextPromise) {
|
||
reject(new TypeError(CHAINING_CYCLE));
|
||
} else {
|
||
call(resolve, reject, value);
|
||
}
|
||
}
|
||
function asyncOnFulfilled() {
|
||
setImmediate(tryCall, onFulfilled);
|
||
}
|
||
function asyncOnRejected() {
|
||
setImmediate(tryCall, onRejected);
|
||
}
|
||
switch (promise[STATUS]) {
|
||
case FULFILLED:
|
||
asyncOnFulfilled();
|
||
break;
|
||
case REJECTED:
|
||
asyncOnRejected();
|
||
break;
|
||
default:
|
||
enqueue(promise, asyncOnFulfilled, asyncOnRejected);
|
||
}
|
||
});
|
||
return nextPromise;
|
||
};
|
||
|
||
Promise.prototype['catch'] = function (onRejected) {
|
||
return this.then(identity, onRejected);
|
||
};
|
||
|
||
Promise.resolve = function (value) {
|
||
var anything = toPromise(value);
|
||
if (isPromise(anything)) {
|
||
return anything;
|
||
}
|
||
return new Promise(function (resolve, reject) {
|
||
if (isInternalError(anything)) {
|
||
reject(anything[ORIGINAL_ERROR]);
|
||
} else {
|
||
resolve(value);
|
||
}
|
||
});
|
||
};
|
||
|
||
Promise.reject = function (reason) {
|
||
return new Promise(function (resolve, reject) {
|
||
reject(reason);
|
||
});
|
||
};
|
||
|
||
Promise.race = function (values) {
|
||
return new Promise(function (resolve, reject) {
|
||
var i;
|
||
var length;
|
||
if (isArray(values)) {
|
||
length = values.length;
|
||
for (i = 0; i < length; i++) {
|
||
call(resolve, reject, values[i]);
|
||
}
|
||
} else {
|
||
reject(new TypeError(NOT_ARRAY));
|
||
}
|
||
});
|
||
};
|
||
|
||
Promise.all = function (values) {
|
||
return new Promise(function (resolve, reject) {
|
||
var fulfilledCount = 0;
|
||
var promiseCount = 0;
|
||
var anything;
|
||
var length;
|
||
var value;
|
||
var i;
|
||
if (isArray(values)) {
|
||
values = values.slice(0);
|
||
length = values.length;
|
||
for (i = 0; i < length; i++) {
|
||
value = values[i];
|
||
anything = toPromise(value);
|
||
if (isPromise(anything)) {
|
||
promiseCount++;
|
||
anything.then(
|
||
function (index) {
|
||
return function (value) {
|
||
values[index] = value;
|
||
fulfilledCount++;
|
||
if (fulfilledCount == promiseCount) {
|
||
resolve(values);
|
||
}
|
||
};
|
||
}(i),
|
||
reject
|
||
);
|
||
} else if (isInternalError(anything)) {
|
||
reject(anything[ORIGINAL_ERROR]);
|
||
} else {
|
||
//[1, , 3] → [1, undefined, 3]
|
||
values[i] = value;
|
||
}
|
||
}
|
||
if (!promiseCount) {
|
||
resolve(values);
|
||
}
|
||
} else {
|
||
reject(new TypeError(NOT_ARRAY));
|
||
}
|
||
});
|
||
};
|
||
|
||
if (typeof module != 'undefined' && module.exports) {
|
||
module.exports = global.Promise || Promise;
|
||
} else if (!global.Promise) {
|
||
global.Promise = Promise;
|
||
}
|
||
|
||
}(this)); |