zalgo-promise
Version:
Javascript module template.
445 lines (365 loc) • 10.7 kB
JavaScript
import { isPromise as _isPromise } from './utils';
import { onPossiblyUnhandledException as _onPossiblyUnhandledException, dispatchPossiblyUnhandledError } from './exceptions';
import { startActive, endActive, awaitActive } from './flush';
export var ZalgoPromise = /*#__PURE__*/function () {
// eslint-disable-next-line flowtype/no-mutable-array
function ZalgoPromise(handler) {
var _this = this;
this.resolved = void 0;
this.rejected = void 0;
this.errorHandled = void 0;
this.value = void 0;
this.error = void 0;
this.handlers = void 0;
this.dispatching = void 0;
this.stack = void 0;
this.resolved = false;
this.rejected = false;
this.errorHandled = false;
this.handlers = [];
if (handler) {
var _result;
var _error;
var resolved = false;
var rejected = false;
var isAsync = false;
startActive();
try {
handler(function (res) {
if (isAsync) {
_this.resolve(res);
} else {
resolved = true;
_result = res;
}
}, function (err) {
if (isAsync) {
_this.reject(err);
} else {
rejected = true;
_error = err;
}
});
} catch (err) {
endActive();
this.reject(err);
return;
}
endActive();
isAsync = true;
if (resolved) {
// $FlowFixMe
this.resolve(_result);
} else if (rejected) {
this.reject(_error);
}
}
if (__DEBUG__) {
try {
throw new Error("ZalgoPromise");
} catch (err) {
this.stack = err.stack;
}
}
}
var _proto = ZalgoPromise.prototype;
_proto.resolve = function resolve(result) {
if (this.resolved || this.rejected) {
return this;
}
if (_isPromise(result)) {
throw new Error('Can not resolve promise with another promise');
}
this.resolved = true;
this.value = result;
this.dispatch();
return this;
};
_proto.reject = function reject(error) {
var _this2 = this;
if (this.resolved || this.rejected) {
return this;
}
if (_isPromise(error)) {
throw new Error('Can not reject promise with another promise');
}
if (!error) {
// $FlowFixMe
var _err = error && typeof error.toString === 'function' ? error.toString() : Object.prototype.toString.call(error);
error = new Error("Expected reject to be called with Error, got " + _err);
}
this.rejected = true;
this.error = error;
if (!this.errorHandled) {
setTimeout(function () {
if (!_this2.errorHandled) {
dispatchPossiblyUnhandledError(error, _this2);
}
}, 1);
}
this.dispatch();
return this;
};
_proto.asyncReject = function asyncReject(error) {
this.errorHandled = true;
this.reject(error);
return this;
};
_proto.dispatch = function dispatch() {
var dispatching = this.dispatching,
resolved = this.resolved,
rejected = this.rejected,
handlers = this.handlers;
if (dispatching) {
return;
}
if (!resolved && !rejected) {
return;
}
this.dispatching = true;
startActive();
var chain = function chain(firstPromise, secondPromise) {
return firstPromise.then(function (res) {
secondPromise.resolve(res);
}, function (err) {
secondPromise.reject(err);
});
};
for (var i = 0; i < handlers.length; i++) {
var _handlers$i = handlers[i],
onSuccess = _handlers$i.onSuccess,
onError = _handlers$i.onError,
promise = _handlers$i.promise;
var _result2 = void 0;
if (resolved) {
try {
_result2 = onSuccess ? onSuccess(this.value) : this.value;
} catch (err) {
promise.reject(err);
continue;
}
} else if (rejected) {
if (!onError) {
promise.reject(this.error);
continue;
}
try {
_result2 = onError(this.error);
} catch (err) {
promise.reject(err);
continue;
}
}
if (_result2 instanceof ZalgoPromise && (_result2.resolved || _result2.rejected)) {
var promiseResult = _result2;
if (promiseResult.resolved) {
promise.resolve(promiseResult.value);
} else {
promise.reject(promiseResult.error);
}
promiseResult.errorHandled = true;
} else if (_isPromise(_result2)) {
if (_result2 instanceof ZalgoPromise && (_result2.resolved || _result2.rejected)) {
if (_result2.resolved) {
promise.resolve(_result2.value);
} else {
promise.reject(_result2.error);
}
} else {
// $FlowFixMe
chain(_result2, promise);
}
} else {
promise.resolve(_result2);
}
}
handlers.length = 0;
this.dispatching = false;
endActive();
};
_proto.then = function then(onSuccess, onError) {
if (onSuccess && typeof onSuccess !== 'function' && !onSuccess.call) {
throw new Error('Promise.then expected a function for success handler');
}
if (onError && typeof onError !== 'function' && !onError.call) {
throw new Error('Promise.then expected a function for error handler');
}
var promise = new ZalgoPromise();
this.handlers.push({
promise: promise,
onSuccess: onSuccess,
onError: onError
});
this.errorHandled = true;
this.dispatch();
return promise;
};
_proto.catch = function _catch(onError) {
// $FlowFixMe incompatible-call
var resultPromise = this.then(undefined, onError);
return resultPromise;
};
_proto.finally = function _finally(onFinally) {
if (onFinally && typeof onFinally !== 'function' && !onFinally.call) {
throw new Error('Promise.finally expected a function');
}
return this.then(function (result) {
return ZalgoPromise.try(onFinally).then(function () {
return result;
});
}, function (err) {
return ZalgoPromise.try(onFinally).then(function () {
throw err;
});
});
};
_proto.timeout = function timeout(time, err) {
var _this3 = this;
if (this.resolved || this.rejected) {
return this;
}
var timeout = setTimeout(function () {
if (_this3.resolved || _this3.rejected) {
return;
}
_this3.reject(err || new Error("Promise timed out after " + time + "ms"));
}, time);
return this.then(function (result) {
clearTimeout(timeout);
return result;
});
} // $FlowFixMe
;
_proto.toPromise = function toPromise() {
// $FlowFixMe
if (typeof Promise === 'undefined') {
throw new TypeError("Could not find Promise");
} // $FlowFixMe
return Promise.resolve(this); // eslint-disable-line compat/compat
};
_proto.lazy = function lazy() {
this.errorHandled = true;
return this;
};
ZalgoPromise.resolve = function resolve(value) {
if (value instanceof ZalgoPromise) {
// $FlowFixMe incompatible-type-arg
var _result3 = value;
return _result3;
}
if (_isPromise(value)) {
// $FlowFixMe
return new ZalgoPromise(function (resolve, reject) {
return value.then(resolve, reject);
});
}
return new ZalgoPromise().resolve(value);
};
ZalgoPromise.reject = function reject(error) {
return new ZalgoPromise().reject(error);
};
ZalgoPromise.asyncReject = function asyncReject(error) {
return new ZalgoPromise().asyncReject(error);
};
ZalgoPromise.all = function all(promises) {
// eslint-disable-line no-undef
var promise = new ZalgoPromise();
var count = promises.length; // eslint-disable-next-line no-undef
var results = [].slice();
if (!count) {
promise.resolve(results);
return promise;
}
var chain = function chain(i, firstPromise, secondPromise) {
return firstPromise.then(function (res) {
results[i] = res;
count -= 1;
if (count === 0) {
promise.resolve(results);
}
}, function (err) {
secondPromise.reject(err);
});
};
for (var i = 0; i < promises.length; i++) {
var prom = promises[i];
if (prom instanceof ZalgoPromise) {
if (prom.resolved) {
results[i] = prom.value;
count -= 1;
continue;
}
} else if (!_isPromise(prom)) {
results[i] = prom;
count -= 1;
continue;
}
chain(i, ZalgoPromise.resolve(prom), promise);
}
if (count === 0) {
promise.resolve(results);
}
return promise;
};
ZalgoPromise.hash = function hash(promises) {
// eslint-disable-line no-undef
var result = {};
var awaitPromises = [];
var _loop = function _loop(key) {
if (promises.hasOwnProperty(key)) {
var value = promises[key];
if (_isPromise(value)) {
awaitPromises.push(value.then(function (res) {
result[key] = res;
}));
} else {
result[key] = value;
}
}
};
for (var key in promises) {
_loop(key);
}
return ZalgoPromise.all(awaitPromises).then(function () {
return result;
});
};
ZalgoPromise.map = function map(items, method) {
// $FlowFixMe
return ZalgoPromise.all(items.map(method));
};
ZalgoPromise.onPossiblyUnhandledException = function onPossiblyUnhandledException(handler) {
return _onPossiblyUnhandledException(handler);
};
ZalgoPromise.try = function _try(method, context, args) {
if (method && typeof method !== 'function' && !method.call) {
throw new Error('Promise.try expected a function');
}
var result;
startActive();
try {
result = method.apply(context, args || []);
} catch (err) {
endActive();
return ZalgoPromise.reject(err);
}
endActive(); // $FlowFixMe incompatible-call
var resultPromise = ZalgoPromise.resolve(result);
return resultPromise;
};
ZalgoPromise.delay = function delay(_delay) {
return new ZalgoPromise(function (resolve) {
setTimeout(resolve, _delay);
});
};
ZalgoPromise.isPromise = function isPromise(value) {
if (value && value instanceof ZalgoPromise) {
return true;
}
return _isPromise(value);
};
ZalgoPromise.flush = function flush() {
return awaitActive(ZalgoPromise);
};
return ZalgoPromise;
}();