Last active
February 24, 2020 16:58
-
-
Save sketchpunk/0240ddf7dd5c81f894ec3a65e90a9447 to your computer and use it in GitHub Desktop.
XhrPromise = XMLHttpRequest + Promise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
let xhr = new XhrPromise(); | |
xhr.get(url, "json").then( r=>console.log(r) ).catch(err=>console.log(err)); | |
*/ | |
class XhrPromise{ | |
static get( url, type ){ | |
let xhr = new XhrPromise(); | |
return xhr.get.apply( xhr, arguments ); | |
} | |
constructor(){ | |
this.xhr = new XMLHttpRequest(); | |
this.xhr.addEventListener("load", this.onXhrComplete.bind( this ) ,false); | |
this.xhr.addEventListener("error", this.onXhrError.bind( this ) ,false); | |
this.xhr.addEventListener("abort", this.onXhrAbort.bind( this ) ,false); | |
this.xhr.addEventListener("timeout", this.onXhrTimeout.bind( this ) ,false); | |
this.total_items = 0; | |
this.queue = null; | |
this.complete = null; | |
this.progress_cb = null; | |
this.url = null; | |
this.resType = null; | |
//Start request in promise and save Resolve/Reject reference to call later | |
//when the async xhr call is complete. | |
this._onPromise = ( resolve, reject )=>{ | |
this.promiseResolve = resolve; | |
this.promiseReject = reject; | |
if( this.queue != null ) this._queueNext(); | |
else this._get(); | |
}; | |
} | |
on_progress( cb ){ | |
this.progress_cb = cb; | |
this.xhr.addEventListener("progress", this.onXhrProgress.bind( this ) ,false); | |
return this; | |
} | |
get( url, type ){ | |
if( arguments.length > 2 ){ | |
this.queue = new Array(); | |
this.complete = new Array(); | |
for(let i=0; i < arguments.length; i+=2 ){ | |
this.queue.push({ url:arguments[i], type:arguments[i+1] }); | |
} | |
this.total_items = this.queue.length; | |
}else{ | |
this.url = url; | |
this.resType = type; | |
} | |
return new Promise( this._onPromise ); | |
} | |
_queueNext(){ | |
if( this.queue.length == 0 ) return false; | |
let itm = this.queue.shift(); | |
this.url = itm.url; | |
this.resType = itm.type; | |
this._get(); | |
return true; | |
} | |
_get(){ | |
//console.log("GET", this.url, this.resType ); | |
this.xhr.open( "GET", this.url, true ); | |
this.xhr.responseType = this.resType || "text"; | |
try{ | |
this.xhr.send(); | |
}catch(err){ | |
console.error("xhr err",err); | |
this._complete( false, err ); | |
} | |
} | |
_complete( isSuccess, err ){ | |
//console.log( "Complete", isSuccess, err ); | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
if( !isSuccess ){ | |
this.promiseReject( err ); | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
}else{ | |
// Handling a queue of items. | |
if( this.queue ){ | |
this.complete.push( this.xhr.response ); | |
if( this._queueNext() ) return; | |
this.promiseResolve( this.complete ); | |
}else{ | |
this.promiseResolve( this.xhr.response ); | |
} | |
} | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
this.queue = null; | |
this.complete = null; | |
this.url = null; | |
this.resType = null; | |
} | |
onXhrComplete( e ){ //console.log( e, e.currentTarget.response ); | |
if(this.xhr.status != 200) this._complete( false, "http status : " + this.xhr.status + " " + this.xhr.statusText ); | |
else this._complete( true ); | |
} | |
onXhrError( e ){ this._complete( false ); console.error("onXhrError"); } | |
onXhrAbort( e ){ this._complete( false ); console.error("onXhrAbort"); } | |
onXhrTimeout( e ){ this._complete( false ); console.error("onXhrTimeout"); } | |
onXhrProgress( e ){ | |
let itms = (this.queue)? this.queue.length+1 : 0, | |
prog = e.loaded, | |
total = e.total, | |
per = prog / total; | |
console.log( this.total_items - itms, this.total_items, prog, total, per); | |
} | |
} | |
export default XhrPromise; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class XhrPromise{ | |
xhr = new XMLHttpRequest(); | |
mode = ""; | |
url = null; | |
body = null; | |
body_type = null; | |
res_type = "text"; | |
resolve = null; | |
reject = null; | |
active = false; | |
constructor(){ | |
this.xhr.self = this; | |
this.xhr.addEventListener( "load", XhrPromise.on_complete, false); | |
this.xhr.addEventListener( "error", XhrPromise.on_error , false); | |
this.xhr.addEventListener( "abort", XhrPromise.on_abort, false); | |
this.xhr.addEventListener( "timeout", XhrPromise.on_timeout, false); | |
} | |
get( url, res_type ){ | |
if( this.active ) return null; | |
this.url = url; | |
this.res_type = res_type || "text"; | |
this.mode = "GET"; | |
this.body = null; | |
return new Promise( this._promise.bind( this ) ); | |
} | |
post( url, body, res_type, body_type ){ | |
if( this.active ) return null; | |
this.url = url; | |
this.res_type = res_type || "text"; | |
this.mode = "POST"; | |
if( body ){ | |
if( body instanceof FormData ){ | |
this.body = body; | |
this.body_type = null; //"form" FromData changes the Content-Type to whatever it needs to use. So no point assigning it. | |
}else if( Array.isArray( body ) || typeof body === "object" ){ | |
this.body = JSON.stringify( body ); | |
this.body_type = "json"; | |
}else{ | |
this.body = body; | |
} | |
} | |
if( body_type ) this.body_type = body_type; | |
return new Promise( this._promise.bind( this ) ); | |
} | |
_promise( resolve, reject ){ | |
this.resolve = resolve; | |
this.reject = reject; | |
this.active = true; | |
this.xhr.open( this.mode, this.url, true ); | |
this.xhr.responseType = this.res_type; | |
/* console.log( this.body_type, this.body ); */ | |
switch( this.body_type ){ | |
case "json": this.xhr.setRequestHeader( "Content-Type", "application/json;charset=UTF-8" ); break; | |
case "form": this.xhr.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" ); break; | |
case "multi": this.xhr.setRequestHeader( "Content-Type", "multipart/form-data" ); break; | |
} | |
try{ this.xhr.send( this.body ); } | |
catch( err ){ this._complete( false, err ); } | |
}; | |
_complete( isSuccess, err ){ | |
//console.log( "xhr_complete", isSuccess, err ); | |
if( !isSuccess ) this.reject( err ); | |
else{ | |
// IE11 doesn't support response types, | |
// So if requesting a JSON response, Parse it before returning it. | |
let rtn; | |
if( this.res_type == "json" && typeof this.xhr.response == "string" ){ | |
rtn = JSON.parse( this.xhr.response ); | |
}else{ | |
rtn = this.xhr.response; | |
} | |
this.resolve( rtn ); | |
} | |
this.dispose(); | |
} | |
dispose(){ | |
this.resolve = null; | |
this.reject = null; | |
this.xhr.self = null; | |
this.xhr.removeEventListener( "load", XhrPromise.on_complete, false ); | |
this.xhr.removeEventListener( "error", XhrPromise.on_error , false ); | |
this.xhr.removeEventListener( "abort", XhrPromise.on_abort, false ); | |
this.xhr.removeEventListener( "timeout", XhrPromise.on_timeout, false ); | |
} | |
static on_error = function( e ){ this.self._complete( false ); console.error("onXhrError"); } | |
static on_abort = function( e ){ this.self._complete( false ); console.error("onXhrAbort"); } | |
static on_timeout = function( e ){ this.self._complete( false ); console.error("onXhrTimeout"); } | |
static on_complete = function( e ){ //console.log( e, e.currentTarget.response ); | |
let xhr = e.srcElement; | |
if( xhr.status != 200 ) xhr.self._complete( false, "http status : " + xhr.status + " " + xhr.statusText ); | |
else xhr.self._complete( true ); | |
} | |
static get( url, type ){ return new XhrPromise().get( url, type ); } | |
static post( url, body, res_type, body_type ){ return new XhrPromise().post( url, body, res_type, body_type ); } | |
} | |
window.XhrPromise = XhrPromise; | |
export default XhrPromise; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment