-
-
Save dmethvin/43ffd1c743554e5c50ae to your computer and use it in GitHub Desktop.
// Node-like signature with single callback, returns the XHR | |
$.xhrcb( url: String, complete: Function( err: Error, xhr: XHR, options: Object ) ): XHR; | |
$.xhrcb( options: Object, complete: Function( err: Error, xhr: XHR, options: Object ) ): XHR; | |
// Returns a Promise, throws an error if no Promise or shim | |
$.xhr( options: Object ): Promise | |
// See ticket http://bugs.jquery.com/ticket/14509 for `options` | |
// Thoughts: | |
// * `options` should not include callbacks! Expose functionality | |
// by passing in functions or chaining Promise. | |
// * May need to allow beforeSend option as an escape hatch. | |
// * `err` here does not try to judge success by HTTP status, that can | |
// be done at another level (see examples below). | |
// * I've separated out the entity data from the url data to avoid needing | |
// to guess where it goes and allow BOTH to be used in a request. | |
// ------------------- EXAMPLES ------------------- | |
// Basic GET request, using complete callback | |
$.xhrcb({ url: "/user/1234" }, function( err, xhr, options ) { | |
if ( err || xhr.status !== 200 ) { | |
// Something went wrong, examine err and xhr | |
return; | |
} | |
var user = $.parseJSON( xhr.responseText ); | |
// Note that `user` could be `null` here... | |
console.log( "Name: ", user.name ); | |
}); | |
// Use helper to break into $.ajax-like error/success callbacks | |
$.xhrcb("/user/1234", $.xhr.toSuccessError( | |
function( user, xhr, options ) { | |
console.log( "Name: ", user.name ); | |
}, | |
function( err, xhr, options ) { | |
console.log( "Error: " + err + " " + xhr.status ); | |
} | |
)); | |
// GET request known to return JSON, using Promise | |
$.xhr( "/user/123/" ) | |
.then( $.xhr.toJSON ) | |
.then( function( user ) { | |
console.log( "Name: ", user.name ); | |
}) | |
.catch( function( err ) { | |
console.error( "Error: ", err ); | |
}); | |
// POST request where we only care about success | |
$.xhr({ | |
url: "/user/create/", | |
method: "POST", | |
body: { name: "Dave", awesome: true, city: "Columbia" } | |
}) | |
.then( | |
function() { | |
console.log( "User created" ); | |
}, | |
function( err ) { | |
console.error( err.message ); | |
} | |
); | |
// POST with a single retry if the server is busy. Assume we add the xhr | |
// and options as a property of the Error object so it can be accessed. | |
$.xhr({ | |
url: "/user/create/", | |
method: "POST", | |
body: { name: "Dave", awesome: true, city: "Columbia" } | |
}) | |
.catch( function( err ) { | |
// If the server was busy, retry once | |
if ( err.xhr && err.xhr.status === 408 ) { | |
return $.xhr( err.options ); | |
} | |
// Some other error, re-throw and we'll catch below | |
throw( err ); | |
}) | |
.then( function() { | |
console.log( "User created" ); | |
}) | |
.catch( function( err ) { | |
// We could be specific with .options and .xhr if needed | |
console.error( err.message ); | |
}); | |
// GET where the caller wants us to guess type based on response, | |
// pretty much like $.ajax but with the type returned | |
$.xhr( "/user/123/" ) | |
.then( $.xhr.toContentType ) | |
.then( function( response ) { | |
if ( response.type !== "json" ) { | |
throw( "I WANT JSON" ); | |
} | |
console.log( "Name: ", response.data.name ); | |
}) | |
.catch( function( err ) { | |
console.error( err ); | |
}); | |
// ------------------- Helpers ------------------- | |
// Helper to create error/success callback based on HTTP code and | |
// convert types, similar to current jQuery $.ajax distinction. | |
// N.B. I think this should be a plugin rather than built in | |
jQuery.xhr.toSuccessError = function( successFn, errorFn ) { | |
return function( err, xhr, options ) { | |
// Call errorFn if err or xhr.status !== 2xx or conversion fails, | |
// otherwise call sucessFn with converted data | |
}; | |
}; | |
// Any $.xhr caller could also use xhr.response directly in XHR2 | |
// as long as xhr.responseType was set before the call. | |
// (So should we do that as part of options processing?) | |
jQuery.xhr.toJSON = function( xhr ) { | |
return jQuery.parseJSON( xhr.responseText ); | |
}; | |
jQuery.xhr.toDOM = function( xhr ) { | |
return jQuery.parseHTML( xhr.responseText ); | |
}; | |
jQuery.xhr.toText = function( xhr ) { | |
return xhr.responseText; | |
}; | |
jQuery.xhr.toScript = function( xhr ) { | |
return jQuery.globalEval( xhr.responseText ); | |
}; | |
jQuery.xhr.toContentType( xhr ) { | |
// Look at Content-Type of response to determine what to | |
// return, similar to "intelligent guess" in $.ajax | |
return { | |
type: "json", | |
data: { }, | |
xhr: xhr | |
}; | |
}; | |
jQuery.xhr.factory = function() { | |
return new XMLHttpRequest(); | |
}; | |
Hello I have some suggestions and equiries here :
1- I have seen that some javascript libraries can transform any thenable to a promise. Take for example : https://github.com/cujojs/when/blob/master/docs/api.md#when. I was thinking of a small thenable (Acting like an equivalent callback) version that can be coerced to a promise. There is some mechanism in every library, including W3C version of Promise : https://github.com/domenic/promises-unwrapping. At "compilation" step, any promise library can be plugged in, there is any dependance on any particular library.
2- Is there a way to have a factory mechanism to xhr ? So that, you can create a sandboxed version of the object and have a scoped set of default configurations. $.xhrFactory(defaultSettings).
3- How can we access the base XHR ? Thinking of it, it made me thinking why don't we have just a lightweight mechanism like ?
- $.xhr( XHR ).set({url:, type: }).request().then(successCallBack, errorCallBack);
or like this ? - var jqXHR = $.xhr({url: type});
jqXHR.get('url');
jqXHR.set({url: 'request/'});
jqXHR.request().then(function () { });
Simply, having xhr as a thin layer to the base XHR, that simplify its programming in a cross browser way. That's my personal opinion.
Gist updated ...