Cross-browser AJAX library



  • Anyone knows any good cross-browser ajax library? I need CORS and cross browser normalization for IE9+.

    So far, I have struck out with:

    superagent
    • No IE9 CORS support, even though they claim they support IE9+
    xdr
    • Crappy JSON handling, it would just crash on empty JSON response, for example
    • It has "json" option, but it doesn't seem to work (have to set headers manually)
    • Low popularity (no stars)

    This one seems like it could do what I want, but due to these factors, I have low confidence in it. It's a fallback in case nothing else is better.

    reqwest
    • Returns a raw XMLHttpRequest object. I mean, if I wanted to deal with that shit, I'd just write my own code.
    JQUERY

    I should already have jQuery loaded up on the page, but due to the way this script will be used, I have no idea which version. I guess I could bring in my own, but that seems wasteful. Also, jQuery's ajax implementation isn't exactly known for its quality.

    Any ideas?



  • Back to trying to make XDR work.

    0_1501072650292_f23e0024-f7fa-474a-813c-8c5f8e0c14d0-image.png

    packet is here undefined on IE9.

    Did no one test this shit!?

    AGH.



  • I guess I could do axios, but then I'd have to eat up promises and its large size.

    And now my mettle is coming up and I am out of time. I can't believe I've wasted 3 hours on something this simple.


  • I survived the hour long Uno hand

    @cartman82 said in Cross-browser AJAX library:

    I have no idea which version

    The basic AJAX behavior I don't think changes often.



  • RestyGWT



  • @yamikuronue said in Cross-browser AJAX library:

    I have no idea which version

    The basic AJAX behavior I don't think changes often.

    But jQuery 1.x has all sorts of browser polyfills and 2.x has less and 3.x is basically evergreen. I can't rely on the right thing being available globally. And I don't want to bring in my own jQuery just for this.



  • @jazzyjosh said in Cross-browser AJAX library:

    RestyGWT

    What the hell, that looks like Java. Down which dark alleys are you leading me?



  • @cartman82 That's correct.

    Please get in the van. We have coffee and bagels.



  • @jazzyjosh said in Cross-browser AJAX library:

    @cartman82 That's correct.
    Please get in the van. We have coffee and bagels.

    Wow mister, you sure do have a looong abstract constructor factory chain there.


  • SockDev

    @cartman82 said in Cross-browser AJAX library:

    But jQuery 1.x has all sorts of browser polyfills and 2.x has less and 3.x is basically evergreen.

    And they all fully support IE9 ;)



  • @cartman82 Let's not compare class name lengths. :giggity:



  • @raceprouk said in Cross-browser AJAX library:

    And they all fully support IE9

    Hmm.. Good point.

    Maybe I am overthinking this. I think I'll just wrap jQuery.ajax and see what happens.



  • @cartman82 Isn't the standard here still jQuery? Is there a reason you're not using that?

    EDIT: oh you put that explanation dead-last.

    If you don't know what libraries are available on the page, I assume you're writing something like an analytics script that'll be deployed essentially randomly to client sites. In that case, I'd write raw JS/DOM 100%. Any dependency you pull in is going to cause a compatibility issue sooner or later-- trust me, I built JS like that for 5 years, and I'm back doing it now.

    Dealing with AJAX isn't hard. Your biggest challenge is CORS on IE9. (And, BTW:

    1. You probably don't need CORS if you're just sending-- put your data in the query string of a pixel.gif request on your server.
    2. If you do need 2-way communication, you can evaluate whether good old fashioned JSONP works for you. It's a hell of a lot easier to implement in raw JS/DOM code.)

    BTW, jQuery is also open source, you could just tear out its working AJAX implementation and integrate it in your own product without using the rest of jQuery.



  • @blakeyrat said in Cross-browser AJAX library:

    If you don't know what libraries are available on the page, I assume you're writing something like an analytics script that'll be deployed essentially randomly to client sites. In that case, I'd write raw JS/DOM 100%. Any dependency you pull in is going to cause a compatibility issue sooner or later-- trust me, I built JS like that for 5 years, and I'm back doing it now.

    Yes, I am doing analytics things. But it will be limited to a specific network of websites, that are aimed at more modern browsers and already have jQuery as a requirement (I just can't guarantee which version). So since I am not trying to make a general purpose library, I can get away with a bit more leeway in what I support.

    I don't think I'll have script conflicts though, since I'm packaging everything using babel + browserify. But that also means I am trying to limit external dependencies as much as possible, which is why I was trying to bring in something tiny and specialized, without packaging the entire jQuery.

    Dealing with AJAX isn't hard. Your biggest challenge is CORS on IE9. (And, BTW:

    • You probably don't need CORS if you're just sending-- put your data in the query string of a pixel.gif request on your server.
    • If you do need 2-way communication, you can evaluate whether good old fashioned JSONP works for you. It's a hell of a lot easier to implement in raw JS/DOM code.)

    That's an interesting idea. I need one 2-way message to set up the session, but afterwards, it's all one way.

    But wouldn't that mean I'd have to create a new pixel image every time I wanted to send a message? Or just alter an existing image's src? And how would I know the existing url has been "sent" before I set up a new one?

    This seems like an extreme solution for IE6 and earlier browsers.

    I think I'll try to use the jQuery's ajax thing, and then maybe extract the ajax bits if it turns out there are conflicts.



  • @cartman82 said in Cross-browser AJAX library:

    I don't think I'll have script conflicts though, since I'm packaging everything using babel + browserify.

    That's how I'm doing my current project too. It works pretty well, but it makes development a pain in the ass. (No more quick iteration, debugger doesn't match actual code files, etc.) I couldn't figure out how to get browserify to do its thing without putting in a tiny bit of global state, though. Probably just me being an idiot.

    Another issue with analytics is file size. The smaller your script, the more (and higher quality) data you'll collect. So, yeah, dependencies still matter but for different reasons than you think. If I were in charge of your project, I would have kiboshed including jQuery on the basis that it's huge-- you can gather quality metrics, including all DOM events, in 15k or less of script. Again: I know, I've done it.

    @cartman82 said in Cross-browser AJAX library:

    But wouldn't that mean I'd have to create a new pixel image every time I wanted to send a message?

    That's the general solution. Create an array and shove your image elements in it. The images have to exist in the DOM, but you don't have to actually include them on the page. I can dig up some old code if you want to know how I did it exactly.

    @cartman82 said in Cross-browser AJAX library:

    And how would I know the existing url has been "sent" before I set up a new one?

    Serial number them. On your back-end, look for gaps in the sequences and toss out those sessions. (I guess you could try some analysis on them, but with that data it's kind of a "who knows".) Don't expect them to hit your server "in order" necessarily.

    A bigger problem (if you're caching events, and you should be to reduce traffic) is getting the last bit of data before the page is unloaded. I know some tricks for this, too, but I'm not sure if they still work in Chrome (which was the most Nazi about that).

    @cartman82 said in Cross-browser AJAX library:

    This seems like an extreme solution for IE6 and earlier browsers.

    ? That's what literally everybody does all the time. Like... what do you think Google Analytics, Omniture, WebTrends are all doing now? It's way quicker, easier, and more reliable than a hell of a lot of alternative methods. It's not the "extreme" solution, it's the fundamental one every other is compared against.



  • @blakeyrat said in Cross-browser AJAX library:

    That's how I'm doing my current project too. It works pretty well, but it makes development a pain in the ass. (No more quick iteration, debugger doesn't match actual code files, etc.) I couldn't figure out how to get browserify to do its thing without putting in a tiny bit of global state, though. Probably just me being an idiot.

    If you can't get rid of global state any other way, you can just add a module container.js that only exports a single js object (module.exports = {}; or export default {};), and then just attach to that whatever you want to share between other modules.

    I personally attach a bunch of stuff to window, but that is only so I can meddle with stuff and debug in production. I don't need it to share code between modules.

    As for debugger, if you set up code maps, you should get 90% seamless debugger experience. I'm not sure how you have set up your build system, but if you have to debug the giant bundled file or line numbers don't work or something like that, you did it wrong.

    Another issue with analytics is file size. The smaller your script, the more (and higher quality) data you'll collect. So, yeah, dependencies still matter but for different reasons than you think. If I were in charge of your project, I would have kiboshed including jQuery on the basis that it's huge-- you can gather quality metrics, including all DOM events, in 15k or less of script. Again: I know, I've done it.

    15k is impressive.

    I am at 100k now, but there is other stuff included in that script (also more stuff that can be included on case by case basis - it's complicated).

    That's the general solution. Create an array and shove your image elements in it. The images have to exist in the DOM, but you don't have to actually include them on the page. I can dig up some old code if you want to know how I did it exactly.

    Interesting.

    And did you ever take images out of the array? What if a visitor left the tab open for days? Wouldn't that cause a leak?

    A bigger problem (if you're caching events, and you should be to reduce traffic) is getting the last bit of data before the page is unloaded. I know some tricks for this, too, but I'm not sure if they still work in Chrome (which was the most Nazi about that).

    Right now, I just take whatever is left in the message queues (there is a retry system, in case the client temp loses connection), bundle it up in one big message and ajax it out all at once.

    It seems to be working in my tests so far.

    ? That's what literally everybody does all the time. Like... what do you think Google Analytics, Omniture, WebTrends are all doing now? It's way quicker, easier, and more reliable than a hell of a lot of alternative methods. It's not the "extreme" solution, it's the fundamental one every other is compared against.

    TIL. I just checked. You are right. It wouldn't have even occurred to me.

    But I guess it makes sense if you want to target every platform. If it can run javascript and display images, this method should be able to track it.



  • @cartman82 jquery.js?



  • @cartman82 said in Cross-browser AJAX library:

    If you can't get rid of global state any other way, you can just add a module container.js that only exports a single js object (module.exports = {}; or export default {};), and then just attach to that whatever you want to share between other modules.

    It needs about... 7 lines of init code. (Basically creating a JSON configuration object to pass into one of the modules.) I tried putting it in a self-contained function but for some reason browserify.js couldn't figure out that it should actually have been including those dependencies. Once I removed the wrapping function, it worked ok. I haven't bothered to go back and debug what the problem was.

    @cartman82 said in Cross-browser AJAX library:

    As for debugger, if you set up code maps, you should get 90% seamless debugger experience.

    Yeah I don't know how to do that. My "build process" is a PowerShell script that copies a few files then runs browserify. Since the files are served in a Chrome extension I'm not sure Chrome would know how to find the "map" anyway. (Or is it embedded into the file somehow?)

    So yes I did it wrong. What the fuck ever. I'd rather have no build process at all and just fucking hit Refresh, which is what I'd have if require.js worked in the Chrome extension environment.

    @cartman82 said in Cross-browser AJAX library:

    15k is impressive.

    It beat the shit out of Omniture, which gathered a lot less data and used a shitload more JS to do it. (Omniture also had fun and weird bugs, when I took a look at it once, including one that could freeze-up a browser. And that was in the days before "the JavaScript running in this page is locked up" dialogs in browsers!) Omniture also at the time dedicated a LOT of script to detecting utterly obsolete shit, like what version of the Java extension was installed.

    IIRC it beat Google Analytics also.

    Unminified it was about 55-60k, IIRC.

    @cartman82 said in Cross-browser AJAX library:

    And did you ever take images out of the array? What if a visitor left the tab open for days? Wouldn't that cause a leak?

    I honestly don't remember. I wager probably not? I'd have to dig up the code and look, frankly. As for "leak", that leak would be minuscule compared to what most SPAs (the kind of site you'd keep open for days) would have normally. Also, remember we were selling this back in the 2008-2014 timeframe; sites that were expected to remain open for days at a time were a lot more rare then.

    @cartman82 said in Cross-browser AJAX library:

    Right now, I just take whatever is left in the message queues (there is a retry system, in case the client temp loses connection), bundle it up in one big message and ajax it out all at once.
    It seems to be working in my tests so far.

    ... it is? I wonder if Chrome unclenched the anus about that. They used to be total "if your unload handler runs longer than 2 milliseconds or starts any HTTP connections, I'll fucking murder it" Nazis. Maybe someone at Google HQ convinced them to relax a bit.

    Kind of a shame, since the exploit I found to defeat that was fucking brilliant.

    @cartman82 said in Cross-browser AJAX library:

    TIL. I just checked. You are right. It wouldn't have even occurred to me.

    There's also a dose of "we've always done it that way", since it was the only working method of web analytics until like... 2006-ish.



  • @blakeyrat said in Cross-browser AJAX library:

    It needs about... 7 lines of init code. (Basically creating a JSON configuration object to pass into one of the modules.) I tried putting it in a self-contained function but for some reason browserify.js couldn't figure out that it should actually have been including those dependencies. Once I removed the wrapping function, it worked ok. I haven't bothered to go back and debug what the problem was.

    Oh I misunderstood. I thought you were using window to share your data between modules. That makes sense.

    I also use window to set up some startup settings. In fact, I then use window as my main shared container (which I architected so that it can be changed later).

    I have a decent idea what code will run on these sites though, so I don't expect it to be a problem.

    So yes I did it wrong. What the fuck ever. I'd rather have no build process at all and just fucking hit Refresh, which is what I'd have if require.js worked in the Chrome extension environment.

    Relax. You did it wrong = you can improve it. It's not an attack.

    Source map can be a separate file (eg. script.js and script.map), but it can also be embedded inside the js file, wherein it should just work.

    I am using browserify from gulp, so my config won't help you. Since it sounds like you are calling browserify directly from CLI, try this:

    0_1501096729462_c4eee548-70c4-408b-bbd6-f2fea53cf2df-image.png

    Docs make it sound like it should add sourcemaps inline, which should suite you well.

    I honestly don't remember. I wager probably not? I'd have to dig up the code and look, frankly. As for "leak", that leak would be minuscule compared to what most SPAs (the kind of site you'd keep open for days) would have normally. Also, remember we were selling this back in the 2008-2014 timeframe; sites that were expected to remain open for days at a time were a lot more rare then.

    Gotcha. That would be death for my use case.

    ... it is? I wonder if Chrome unclenched the anus about that. They used to be total "if your unload handler runs longer than 2 milliseconds or starts any HTTP connections, I'll fucking murder it" Nazis. Maybe someone at Google HQ convinced them to relax a bit.

    Kind of a shame, since the exploit I found to defeat that was fucking brilliant.

    Yeah, seems to be working. Tests in other browsers are pending (been at this for only 3-4 days).

    There's also a dose of "we've always done it that way", since it was the only working method of web analytics until like... 2006-ish.

    Probably.


  • Impossible Mission - B

    @blakeyrat said in Cross-browser AJAX library:

    BTW, jQuery is also open source, you could just tear out its working AJAX implementation and integrate it in your own product without using the rest of jQuery.

    Talking about one of the benefits of open source?

    WHO ARE YOU AND WHAT HAVE YOU DONE TO BLAKEYRAT?!?



  • @cartman82 said in Cross-browser AJAX library:

    I am using browserify from gulp, so my config won't help you. Since it sounds like you are calling browserify directly from CLI, try this:

    Docs make it sound like it should add sourcemaps inline, which should suite you well.

    Fucking hate CLIs.

    "But remember to put the -d BEFORE the -o because if you do it the other way around you'll get errors about not being able to find files, here using the worst, most unfriendly, awful UI in existence nothing that looks like it should work actually does! Fuck you user!" The sad thing is I've been exposed to that shit-storm of a broken ass-UI so long I almostly immediately figured the problem was that order of the flags matters. Also I know what "flags" means when it comes to calling CLI broken shit. Shoot me.

    Oh, thought you were done? Well you're not!

    0_1501097539882_Untitled.png

    Now you have to do... whatever this thing Chrome's telling me I have to do is! Somehow it involves printing(?)! Remember, everything in software development is as annoying and difficult as it's humanly possible to make it. Why would you expect it to just work?

    ... anyway thanks for the tip. But why can't we have good fucking tools? Just once?



  • @blakeyrat said in Cross-browser AJAX library:

    Now you have to do... whatever this thing Chrome's telling me I have to do is! Somehow it involves printing(?)! Remember, everything in software development is as annoying and difficult as it's humanly possible to make it. Why would you expect it to just work?

    Yeah, Ctrl+P is the reason I open the print dialog at least once every few days.

    It's actually a pretty cool feature. Allows you to quickly jump to any file, without having to navigate through the file tree.

    Shame about the shortcut though.



  • @cartman82 said in Cross-browser AJAX library:

    Shame about the shortcut though.

    The fact that nobody at Google gut-punched the person who proposed "control-P" as the shortcut for something other than Print just goes to show how terrible Google engineers actually are.

    Because seriously, just proposing that is gut-punch-worthy.



  • @blakeyrat said in Cross-browser AJAX library:

    Since the files are served in a Chrome extension I'm not sure Chrome would know how to find the "map" anyway. (Or is it embedded into the file somehow?)

    IME with TypeScript and VS-generated source code maps, it works perfectly in Chrome and maps the running code correctly to the original .ts file. A++ would debug again



  • @hungrier said in Cross-browser AJAX library:

    IME with TypeScript and VS-generated source code maps, it works perfectly in Chrome and maps the running code correctly to the original .ts file. A++ would debug again

    See above, it certainly doesn't "work perfectly". Maybe it "works if you jump through some bullshit hoops you don't give a shit about". But definitely not "perfectly".



  • @blakeyrat I don't know about the Ctrl+P business but VS serves the .ts files (and .js.map sourcemaps) along with the .js files, so everything Just Works:tm:. I'm sure there's some way to get browserify to do the same thing with your source files.



  • @blakeyrat said in Cross-browser AJAX library:

    The fact that nobody at Google gut-punched the person who proposed "control-P" as the shortcut for something other than Print just goes to show how terrible Google engineers actually are.
    Because seriously, just proposing that is gut-punch-worthy.

    It's the same shortcut as in sublime text. Maybe that's why they picked it.

    They could have picked Ctrl+Shift+N from WebStorm or Ctrl+, from Visual Studio, though.



  • @hungrier said in Cross-browser AJAX library:

    @blakeyrat I don't know about the Ctrl+P business but VS serves the .ts files (and .js.map sourcemaps) along with the .js files, so everything Just Works. I'm sure there's some way to get browserify to do the same thing with your source files.

    In a Chrome Extension? Remember: I'm talking about a Chrome Extension. AFAIK extensions don't even allow putting .ts files in the archive.

    @cartman82 said in Cross-browser AJAX library:

    It's the same shortcut as in sublime text. Maybe that's why they picked it.

    Ok; so Sublime Text needs to be gut-punched too. Two wrongs doesn't make a right, it makes a "fuck this industry why does everything have to be broken and wrong ALL THE FUCKING TIME WHAT IS WRONG WITH YOU IDIOTS?"



  • @blakeyrat I don't have much experience with developing Chrome extensions so this may be ass-talk but I think whatever's in the extension gets served from a chrome://oiasndoiun4582378dflaiiu389/whatever url, so if you have

    js/minified.js
    js/minified.js.map
    js/original1.js
    js/original2.js
    ...
    

    it should pick up your original source files.



  • @hungrier said in Cross-browser AJAX library:

    it should pick up your original source files.

    With his setup, he is getting source maps inlined, so he doesn't need to worry about that.



  • @cartman82 The maps are in-lined, but the original source files are outside of the extension, presumably why Google Chrome there is asking me to bring up the Print dialog.

    Like I said, AFAIK extensions only allow file types Chrome knows.

    Speaking of things that deserve a gut-punch, using .ts to mark TypeScript files even though .ts is ALREADY a video file format.


  • I survived the hour long Uno hand

    @cartman82 Instead of an array you could put them in a hashmap by timestamp and remove anything an hour old or older.



  • @yamikuronue It'd be less code to do array.push( newimg ); if( array.length > 100 ) { array.shift(); }



  • @blakeyrat unless you have a loss of connection and images get pushed out without connecting to the server.



  • @cartman82 True; but again we were just collecting statistically significant amounts of data. If people fell through the cracks, it was no big deal for our purposes. If your purposes are different, then you might need to do things differently.

    Note that no matter what, you're trusting user's browsers to send you this stuff, you're going to lose data, or get gibberish data. It's simply going to happen. Some sites our script was installed on we had data loss of 2% or more, and that was what we could measure, obviously if the client sends us no data whatsoever we had no way of knowing.


  • Winner of the 2016 Presidential Election

    @blakeyrat said in Cross-browser AJAX library:

    But remember to put the -d BEFORE the -o

    I hate shitty broken tools like that. In any sane CLI interface, the order of the options shouldn't matter at all.



  • @asdf said in Cross-browser AJAX library:

    @blakeyrat said in Cross-browser AJAX library:

    But remember to put the -d BEFORE the -o

    I hate shitty broken tools like that. In any sane CLI interface, the order of the options shouldn't matter at all.

    IIRC, (some?) C compilers allow you to #define and #undef flags from the command-line, and include files to compile using the state of those flags. So compiling -DMYFLAG myfileA.c -D-MYFLAG myfileB.c -DMYFLAG=2 myfileC.c would compile myfileA.c with MYFLAG simply defined, myfileB.c would compile with MYFLAG undefined, and myfileC.c would compile with MYFLAG defined to 2.

    INB4: He said sane CLI.



  • @blakeyrat said in Cross-browser AJAX library:

    Ok; so Sublime Text needs to be gut-punched too.

    You can add VSCode to that list too.

    Or is that an Electron thing?



  • jQuery docs that claims it supports IE8+ are a LIE.

    They DO NOT support Internet Explorer's alternate universe AJAX object, certainly not for CORS requests.

    There are 3rd party plugins to extend jQuery to support it, but then I'd either have to bring my own jQuery or modify a global one with some plugin that does who know what on who knows which versions.

    jQuery is out.

    I am left with either crawling back to the terribly broken xdr, or back to searching for a good lib.

    Or just dropping support for IE9 altogether for now, which is frankly, what I should have done in the first place (the target sites are only tested in IE11 AFAIK).



  • Ugh, this whole thing is a disaster.

    I ended up attaching one of those IE9 CORS plugins to jQuery, fuck it.

    Now the data is coming to the server, but without content-type, so it's not getting parsed (that's because that stupid Microsoft-only AJAX object is "designed" that way). Now I need to figure out how to rewrite that, so it hits all the right handlers on the server

    If I knew adding IE9 support was gonna be this complicated, I'd have never bothered. But now I'm almost there, there's a sunk cost falacy at play. If I give up now, all those hours will go down the drain. So I keep digging.

    Sigh.



  • Finally got it working with this.

    0_1501154838278_94d362f1-3464-44c5-93c0-b20544d0aa52-image.png

    I am not too happy with the mutating global jQuery stuff, but I am all out of time for this feature now.

    Hope to find a better solution in the future.



  • @cartman82 said in Cross-browser AJAX library:

    Or just dropping support for IE9 altogether for now, which is frankly, what I should have done in the first place (the target sites are only tested in IE11 AFAIK).

    If you had told me IE9 was a self-imposed requirement, then yes I probably would have given far different advice. (Well, I kind of did: I said your biggest challenge by far would be getting CORS running on IE9. Next time you should listen to me, and also pay me $500.)



  • @cartman82 I thought it was weird that they were claiming IE9 support for jQuery 2 and 3 since when jQuery 2 originally came out they basically told you IE wasn't supported in it.

    Or was it they claimed it only worked on IE11, I forget, it's been a few years. I know IE9 was explicitly not supported, though.



  • @powerlord They claim IE9+, even for the current jQuery versions.

    I guess that doesn't include a working AJAX though.


  • SockDev

    @cartman82 said in Cross-browser AJAX library:

    @powerlord They claim IE9+, even for the current jQuery versions.

    I guess that doesn't include a working AJAX though.

    AJAX works, just not with CORS.



  • @raceprouk said in Cross-browser AJAX library:

    AJAX works, just not with CORS.

    If this can be made to work with about one page worth of javascript, IMO it's irresponsible not to include it, while claiming full IE9 support.


  • SockDev

    @cartman82 said in Cross-browser AJAX library:

    @raceprouk said in Cross-browser AJAX library:

    AJAX works, just not with CORS.

    If this can be made to work with about one page worth of javascript, IMO it's irresponsible not to include it, while claiming full IE9 support.

    I agree: saying "Oh, just use a plugin" isn't an acceptable response.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.