Skip to content

Instantly share code, notes, and snippets.

@dmethvin
Last active August 29, 2015 14:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmethvin/43ffd1c743554e5c50ae to your computer and use it in GitHub Desktop.
Save dmethvin/43ffd1c743554e5c50ae to your computer and use it in GitHub Desktop.
$.xhr brainstorming
// 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();
};
@tarikbenmerar
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment