suspenders-js
Version:
Asynchronous programming library utilizing coroutines, functional reactive programming and structured concurrency.
122 lines • 3.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.httpGet = exports.promiseSuspender = exports.awaitCancelation = exports.wait = exports.race = exports.async = void 0;
/**
* Starts the suspender but doesn't wait for it's result. Returns a new suspender that returns the
* result.
* @param {Suspender<T>} suspender
* @return {Suspender<T>}
*/
const async = (suspender) => {
let result;
let resultCallback;
return (resCallback) => {
if (result !== undefined) {
resCallback(result);
}
else {
resultCallback = resCallback;
}
return suspender((res) => {
if (resultCallback !== undefined) {
resultCallback(res);
}
else {
result = res;
}
});
};
};
exports.async = async;
/**
* Returns the first suspender to resolve successfully. All other pending suspenders are canceled.
* If all suspenders error, throws the last error.
* @params {Array<Suspender<T>>} suspenders
* @return {Suspender<T>}
*/
const race = (...suspenders) => {
return (resultCallback) => {
const cancelCallbacks = [];
for (let [index, suspender] of suspenders.entries()) {
cancelCallbacks.push(suspender((value) => {
cancelCallbacks[index] = null;
// cancel all other suspenders
for (let m = 0; m < suspenders.length; m++) {
const cancel = cancelCallbacks[m];
if (cancel) {
cancel();
}
else {
cancelCallbacks[m] = null;
}
}
resultCallback(value);
}));
}
return () => {
for (const cancelCallback of cancelCallbacks) {
if (cancelCallback) {
cancelCallback();
}
}
};
};
};
exports.race = race;
/**
* Returns a suspender that resolves with given timout.
* @param {number} millis
* @return {Suspender<void>}
*/
const wait = (millis) => {
return (resultCallback) => {
const timeout = setTimeout(() => {
resultCallback({ value: undefined });
}, millis);
return () => {
clearTimeout(timeout);
};
};
};
exports.wait = wait;
const awaitCancelation = () => {
return () => { };
};
exports.awaitCancelation = awaitCancelation;
/**
* Converts a Promise<T> to a Suspender<T>.
* @param {Promise<T>} promise
* @return {Suspender<T>}
*/
const promiseSuspender = (promise) => {
return (resultCallback) => {
promise.then((value) => { resultCallback({ value }); }, (error) => { resultCallback({ tag: `error`, error }); });
};
};
exports.promiseSuspender = promiseSuspender;
/**
* Performs an http get on url. Returns body on 200 or throws error.
* @param {string} url
* @return {Suspender<T>}
*/
const httpGet = (url) => {
return (resultCallback) => {
const xhttp = new XMLHttpRequest();
xhttp.onloadend = function () {
if (this.status === 200) {
resultCallback({ value: this.responseText });
}
else {
resultCallback({
tag: `error`,
error: new Error(`code: ${this.status} text: ${this.statusText}`)
});
}
};
xhttp.open(`GET`, url, true);
xhttp.send();
return () => { xhttp.abort(); };
};
};
exports.httpGet = httpGet;
//# sourceMappingURL=Util.js.map