@ch1/xhr
Version:
Simple XHR Wrapper
200 lines • 6.33 kB
JavaScript
const json = 'application/json';
const DEFAULT_TIMEOUT = 190000;
const POLL_INTERVAL = 25;
export function Xhr(newXMLHTTPRequest, defaultTimeout = DEFAULT_TIMEOUT, pollInterval = POLL_INTERVAL) {
return XhrConstructor(newXMLHTTPRequest, defaultTimeout, pollInterval);
}
function XhrConstructor(newXMLHTTPRequest, defaultTimeout, pollInterval) {
let XHRReq = newXMLHTTPRequest;
// ensure object constructor
if (!(this instanceof XhrConstructor)) {
return new XhrConstructor(newXMLHTTPRequest, defaultTimeout, pollInterval);
}
const that = this;
/** @dict */
const defaultHttpHeaders = Object.create(null);
init();
/**
* @param {string} key
* @param {string=} value
* @returns {Object}
*/
function defaultHeader(key, value) {
if (!key) {
return defaultHttpHeaders;
}
if (!value) {
if (defaultHttpHeaders[key]) {
delete defaultHttpHeaders[key];
}
}
else {
if (typeof value === 'string') {
defaultHttpHeaders[key] = value;
}
else {
defaultHttpHeaders[key] = value + '';
}
}
return defaultHttpHeaders;
}
/**
* @param {XMLHttpRequest} xhr
*/
function setDefaultHttpHeaders(xhr) {
Object.keys(defaultHttpHeaders).forEach(attr => xhr.setRequestHeader(attr, defaultHttpHeaders[attr]));
}
/**
* @param {XMLHttpRequest} xhr
* @param {Object} localHttpHeaders
*/
function setHttpHeaders(xhr, localHttpHeaders) {
setDefaultHttpHeaders(xhr);
Object.keys(localHttpHeaders).forEach(attr => {
xhr.setRequestHeader(attr, localHttpHeaders[attr] + '');
});
}
/**
* @param {string} method
* @param {string} url
* @param {Object=} queryObj
* @param {Object=} data
* @param {string=} mimeType
* @param {Object=} headers
* @returns {Promise<string>}
*/
function newRequest(method, url, queryObj, data, mimeType, headers) {
return new Promise((resolve, reject) => {
const finalMimeType = mimeType === undefined ? json : mimeType;
const parsedQuery = parseQuery(queryObj);
const finalUrl = parsedQuery ? url + parsedQuery : url;
const xhr = XHRReq();
let timer;
if (method === 'POST' || method === 'PUT') {
if (!data) {
reject(new Error('xhr: newRequest: ' + method + ': requires data'));
return;
}
}
function clearTimer() {
if (timer) {
clearTimeout(timer);
timer = 0;
}
}
/**
* @param {Error} reason
*/
function onerror(reason) {
reject(reason);
clearTimer();
}
function onload() {
// if the document isn't ready try again later
if (+xhr.readyState !== 4) {
setTimeout(onload, pollInterval);
return;
}
// if the header has a 200, or 201 status handle it
if (xhr.status === 200 || xhr.status === 201) {
resolve(xhr.responseText);
clearTimer();
return;
}
// otherwise error/unexpected
onerror(new Error(`xhr: non 200 status: ${xhr.status}`));
}
try {
/** @type {function(...)} */
xhr.onload = onload;
/** @type {function(...)} */
xhr.onerror = onerror;
xhr.open(method, finalUrl, true);
xhr.setRequestHeader('Content-Type', finalMimeType);
if (headers && typeof headers === 'object') {
setHttpHeaders(xhr, headers);
}
else {
setDefaultHttpHeaders(xhr);
}
if (!data) {
xhr.send();
}
else {
xhr.send(JSON.stringify(data));
}
}
catch (e) {
onerror(e);
return;
}
timer = setTimeout(() => {
if (xhr.abort) {
xhr.abort();
}
onerror(new Error('xhr: request timed out'));
}, defaultTimeout);
});
}
/**
* initialize the object
*/
function init() {
XHRReq =
typeof newXMLHTTPRequest === 'function'
? newXMLHTTPRequest
: () => new XMLHttpRequest();
that['defaultHeader'] = defaultHeader;
that['newRequest'] = newRequest;
}
}
/**
* @param {string} url
* @param {Object=} queryObj
* @param {Object=} headers
* @returns {Promise<string>}
*/
XhrConstructor.prototype['get'] = function get(url, queryObj, headers) {
return this['newRequest']('GET', url, queryObj, undefined, undefined, headers);
};
/**
* @param {string} url
* @param {Object=} data
* @param {Object=} queryObj
* @param {Object=} headers
* @returns {Promise<string>}
*/
XhrConstructor.prototype['put'] = function put(url, data, queryObj, headers) {
return this['newRequest']('PUT', url, queryObj, data, undefined, headers);
};
/**
* @param {string} url
* @param {Object=} data
* @param {Object=} queryObj
* @param {Object=} headers
* @returns {Promise<string>}
*/
XhrConstructor.prototype['post'] = function post(url, data, queryObj, headers) {
return this['newRequest']('POST', url, queryObj, data, undefined, headers);
};
/**
* @param {Object=} query
* @returns {string|boolean}
*/
export function parseQuery(query) {
if (!query) {
return false;
}
if (typeof query !== 'object') {
return false;
}
let rString = '?';
Object.keys(query).forEach((i, j) => {
if (j !== 0) {
rString += '&';
}
rString += [i, '=', encodeURIComponent(query[i])].join('');
});
return rString;
}
//# sourceMappingURL=xhr.js.map