UNPKG

libcore

Version:

Kicks-start helpers for cross-browser libraries and different versions of nodejs

270 lines (217 loc) 5.91 kB
'use strict'; import { method, thenable, iterable as isIterable } from "./type.js"; import { assign, instantiate } from "./object.js"; import { setAsync } from "./processor.js"; var slice = Array.prototype.slice, G = global, ERROR_ITERABLE = 'Invalid [iterable] parameter.', INDEX_STATUS = 0, INDEX_DATA = 1, INDEX_PENDING = 2; function createPromise(instance) { var Class = Promise; if (!(instance instanceof Class)) { instance = instantiate(Class); } instance.__state = [null, void(0), [], null, null]; return instance; } function resolveValue(data, callback) { function resolve(data) { try { callback(true, data); } catch (error) { callback(false, error); } } if (thenable(data)) { data.then(resolve, function (error) { callback(false, error); }); } else { resolve(data); } } function finalizeValue(promise, success, data) { var state = promise.__state, list = state[INDEX_PENDING]; state[INDEX_STATUS] = success; state[INDEX_DATA] = data; // notify callbacks for (; list.length; ) { list[0](success, data); list.splice(0, 1); } } function Promise(resolver) { var finalized = false; var instance; function onFinalize(success, data) { finalizeValue(instance, success, data); } function resolve(data) { if (!finalized) { finalized = true; resolveValue(data, onFinalize); } } function reject(error) { if (!finalized) { finalized = true; onFinalize(false, error); } } if (!method(resolver)) { throw new Error('Promise resolver is not a function.'); } instance = createPromise(this); try { resolver(resolve, reject); } catch (error) { reject(error); } return instance; } function resolve(data) { return new Promise(function (resolve) { resolve(data); }); } function reject(reason) { return new Promise(function () { arguments[1](reason); }); } function all(iterable) { var total; function resolver(resolve, reject) { var list = iterable, remaining = total, stopped = false, l = remaining, c = 0, result = []; function process(index, item) { function finalize(success, data) { var found = result; if (stopped) { return; } if (!success) { reject(data); stopped = true; return; } found[index] = data; if (!--remaining) { resolve(found); } } resolveValue(item, finalize); } for (result.length = l; l--; c++) { process(c, list[c]); } } if (!isIterable(iterable)) { throw new TypeError(ERROR_ITERABLE); } iterable = slice.call(iterable, 0); total = iterable.length; if (!total) { return resolve([]); } return new Promise(resolver); } function race(iterable) { function resolver(resolve, reject) { var stopped = false, tryResolve = resolveValue, list = iterable, c = -1, l = list.length; function onFulfill(success, data) { if (!stopped) { stopped = true; (success ? resolve : reject)(data); } } for (; l--;) { tryResolve(list[++c], onFulfill); } } if (!isIterable(iterable)) { throw new TypeError(ERROR_ITERABLE); } iterable = slice.call(iterable, 0); return new Promise(resolver); } Promise.prototype = { constructor: Promise, then: function (onFulfill, onReject) { var me = this, state = me.__state, success = state[INDEX_STATUS], list = state[INDEX_PENDING], instance = createPromise(); function run(success, data) { var finalize = finalizeValue, handle = success ? onFulfill : onReject; if (method(handle)) { try { data = handle(data); resolveValue(data, function (success, data) { finalize(instance, success, data); }); return; } catch (error) { data = error; success = false; } } finalize(instance, success, data); } if (success === null) { list[list.length] = run; } else { setAsync(function () { run(success, state[INDEX_DATA]); }); } return instance; }, "catch": function (onReject) { return this.then(null, onReject); } }; // static methods assign(Promise, { all: all, race: race, reject: reject, resolve: resolve }); // Polyfill if promise is not supported if (!method(G.Promise)) { G.Promise = Promise; } G = null; export default Promise;