Last active
August 29, 2015 14:02
-
-
Save dmethvin/43ffd1c743554e5c50ae to your computer and use it in GitHub Desktop.
$.xhr brainstorming
This file contains hidden or 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
// 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(); | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 ?
or like this ?
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.