Bug Tracker

Opened 8 years ago

Closed 8 years ago

Last modified 6 years ago

#9827 closed enhancement (invalid)

jQuery getScript .text and .async support

Reported by: daveartz Owned by: jaubourg
Priority: low Milestone: 1.next
Component: ajax Version: 1.6.2
Keywords: Cc: dmethvin
Blocked by: Blocking:

Description

Hey guys, more control is needed for loading scripts asynchronously, especially with Google+'s new explicit initialization feature.

Specifically it would be nice to do something like this:

jQuery.getScript("https://apis.google.com/js/plusone.js", { async: true, text: '{"parsetags":"explicit"}', function(){ callback });

I got this working in my Boot library by using the innerHTML property to set the .text, it was the only thing that worked reliably.

https://github.com/artzstudio/Boot/blob/master/src/boot.js (see my getScript for reference).

There are other folks looking to do this cleanly:

http://stackoverflow.com/questions/6207815/issue-loading-google-1-widget-asynchronously

Cheers! Dave Artz

Change History (12)

comment:1 Changed 8 years ago by daveartz

Crap, setting innerHTML on a script node seems to bust IE6.

comment:2 Changed 8 years ago by dmethvin

Hey Dave, can you restate this in the form of a bug report or feature request? Would this best be done by an external script loader, or are you asking for a modest change to $.getScript()?

comment:3 Changed 8 years ago by timmywil

Component: unfiledajax
Owner: set to daveartz
Priority: undecidedlow
Status: newpending

comment:4 Changed 8 years ago by anonymous

Yes, modest change to $.getScript (which I guess is just an alias for certain $.ajax options), which is why I classified as an enhancement.

However I may need to dig a little further as innerHTML threw an error in IE6, maybe I can research this a bit further for you and provide a patch, wouldn't want you to spend effort if this is a relatively low priority.

comment:5 Changed 8 years ago by dmethvin

Just to make this a bit clearer, I think what you're asking for is the ability to set the script tag's inner content before making the request. Correct? It's already async if we use a script tag.

comment:6 Changed 8 years ago by ajpiano

I believe he's asking for the ability to actually have jQuery set the "async" attribute of the script tag that is being created for the request that (which is indeed already async)

http://davidwalsh.name/html5-async

If so, I'd tend to think this should be tacked on as some sort of $.ajax option - I don't really like the idea of suddenly allowing $.getScript to take an config options object where it never has accepted one before

comment:7 Changed 8 years ago by jaubourg

Cc: jaubourg added

So, first of all, an async option to make script tag non async (in the script tag sense of the term) won't work in IE and webkit anyway, so you can forget about that.

If anything, making the script tag async is what makes script loading consistent across browsers: it will be async no matter what. Beside, what most people would expect is the $.ajax call to be synchronous which will never ever happen with script tag injection.

Now one has to give credit to Google for inventing the most unconventional and awkward ways to load scripts in history... so I guess they chose that way because a param string would make cache hits less likely (not by much, mind you). What a poor design decision indeed.

That being said, I really don't see yet another option making it into ajax at this point. However, from what I see in the stackoverflow page, you don't need to actual control script loading (no success callback)... why not do something like:

$( "<script/>", {
    src: "https://apis.google.com/js/plusone.js",
    text: JSON.stringify({
        parsetags: "explicit"
    })
}).appendTo( "head" );

Seems nearly as short as $.getScript and doesn't involve some weird patch for this very specific case.

However, I cannot guarantee that plusone.js doesn't look at the latest script in the head, so if you use getScript after that... well, you could always ask google for a proper, standard, way to load their scripts.

comment:8 Changed 8 years ago by Dave Artz <daveartz@…>

@jaubourg - Fair point on the async / default behavior and I concur, I have no idea what Google was thinking. LinkedIn also does something similar, any ideas why they went this route? Avoiding an inline script following it for cleanliness perhaps... http://developer.linkedinlabs.com/tutorials/jsapi_authentication/

The problem with the $("<script>") technique would be that I wouldn't know when the script loaded, the primary reason I'm looking for a solution in getScript here. I need to set Google+ to explicit mode, and initialize everything after I know the script has loaded and executed.

comment:9 Changed 8 years ago by jaubourg

Cc: dmethvin added; jaubourg removed
Milestone: None1.next
Owner: changed from daveartz to jaubourg
Status: pendingassigned

Hmmm... the madness is spreading it seems ;)

I'm still convinced it's about making sure you hit the cache no matter your config parameters, seems like the only advantage this technique has over a query string in the url (putting it in the script tag that made the request itself makes it much simpler to find and, as opposed to a secondary inline script, avoids a global var declaration or a syntax error when the inline tag is reached by the browser).

The thing is this technique tries to have one's cake and eat it too imo, in the sense an initialization method/function would have worked wonder here, but the guys behind the libs want to do things automagically no matter what: "drop the script and it works", if you see what I mean.

For the time being, you could redefine the script transport found in https://github.com/jquery/jquery/blob/master/src/ajax/script.js: just extract the jQuery.ajaxTransport statement, replace the dataType expression (first parameter) as "+script" to make sure you'll override the existing one and add something like follows just before line 75-77:

if ( s.scriptText ) {
    $( script ).text( s.scriptText );
}

If you drop this redefined transport, you should have a solution to your problem (though you'd need to use ajax rather than getScript):

$.ajax( "https://apis.google.com/js/plusone.js", {
    dataType: "script",
    scriptText: JSON.stringify({
        parsetags: "explicit"
    })
});

Not ideal but it should do the trick for the time being ;)

I'm still pondering if this warrants an inclusion in jQuery (the option would only be local to the script tag injection transport but, still, it's yet another option we'd have to document -- now try and explain this one in plain english btw ;)).

An alternative would be to support some kind of different *type* (is in the ajax option), so that we know data is supposed to be put in the script tag body:

$.ajax( "https://apis.google.com/js/plusone.js", {
    dataType: "script",
    type: "inline",
    data: JSON.stringify({
        parsetags: "explicit"
    })});

I would favour something like this, especially given the script tag injection transport does not support the type option anyway (always normalized it to "get"), though "inline" is not a very good name but heh.

I'd like to have other team members weight in here so that we can try and find a proper solution (knowing the second one has my vote).

comment:10 Changed 8 years ago by Dave Artz <daveartz@…>

Thanks for the advice. I think you can close this issue, I failed at getting IE to create the node with the explicit config and having Google take to it. Tried .innerHTML, .text, and createTextNode.

I'm doing something entirely different now, creating dummy <divs> and doing gapi.plusone.render( $elem[0], options );

Thanks for taking the time to look at this edge case with me :)

comment:11 Changed 8 years ago by jaubourg

Resolution: invalid
Status: assignedclosed

OK, that's good news somehow, probably means the whole system only works with the latest script tag in the document (which always happen for non-dynamic non-async script tags).

As long as there is a way to load things asynchronously, all is good I guess.

comment:12 Changed 6 years ago by anonymous

window['___gcfg'] = { parsetags: 'explicit' };

Note: See TracTickets for help on using tickets.