views:

247

answers:

4

I'm trying to implement fire-and-forget on an img src=... call from a web page, and am looking for the most solid method. Why?

In most Web tracking systems like Omniture or Coremetrics, there is a request for an img src which also happens to carry all the data for the tracking system to record. Like any other image request, the page tries to wait for the response, potentially slowing down the page-load.

What I'm trying to do is implement a tracking system where webpage response time is a much higher priority than whether the request was actually successful, and therefore waiting for the response is totally unnecessary under all conditions, which include...

  1. The server received the request, and can readily respond (HTTP response code 200)
  2. The server received the request, but is bogged down and can still readily respond with an error 500 response code
  3. The server is not running at all
  4. The server was not found due to DNS glitches
  5. The request hit the server, but is so bogged down that it's taking noticeable time to respond.

I have already investigated using the XMLHttpResponse object and an asynchronous request that can quietly fail, but you quickly run into the same origin policy and browser compatibility code bloat. I believe a plain jane img request is still the best request mechanism, but am trying to work out the best fire-and-forget implementation with the smallest amount of code. So far, I know I can...

onerror="this.parentNode.removeChild(this)" onload="this.parentNode.removeChild(this)"

This works pretty well on scenarios 1 through 4 where there is a finite and predictable conclusion to the request. It breaks down in scenario 5, which could be avoided if there were something in-between.

I'm toying with the idea of seeing if this.src.readyState == "complete" but see that I am heading down a road of browser compatiblity and race-condition hell were it would be wise to tap the StackOverflow community first.

Anyone have experience with this and a good solution?

+2  A: 

Why not just add the img tag to your document after it loads?

Pointy
Because it's for a tracking system, it would be nice to make the request initiate as early in the page-load as possible, but that's not a deal-breaker.The main concern is that it doesn't create browser "something is loading" artifacts. I'll check, but my preference is still something early in page display that sends a request but has no capacity to slow page-load (or display loading artifacts)
Mike Levin
A: 

My PoV: User experience comes first, tracking comes next. I have used WebTrends/Omniture & Coremetrics and yes they do give very fine grained details (and later you can segment it the way you want) about the request. Even without these web analytics vendors implemented, you can get a lot of information from your server logs, you just have to do the segmentation yourself (you can log IPs-depending on your Terms & Conditions- and Omniture/Coremetrics do it anyways,Pages requested,action performed like checkout,add to cart, etc).Though these web analytics vendors are very aware of performance and they just send you 1x1 pixel as a response, if their server were slow, your user experience is bad (sometimes happens with google urchins for me, I wait for this one image to load for a very long time). I would think the best way to implement this would be after the document has loaded (jQuery - Document.ready ? ) and then append the <img src="vendor url"/>to the html dom.Even if the request fails or takes a long time, now the user does not feel that the site is unusable

ram
Many people use Akamai, Panther or other content distribution networks, making your own log files difficult to download. Even if you can download them, they may end up being gigabytes to transfer, then to process. With in-code tracking, you can implement filters at the JavaScript level, so calls back to mama are only being made on those conditions you want to record, and the resulting data is megabytes rather than gigabytes.
Mike Levin
The idea of appending an element to the DOM after the page-load has occurred seems to be coming up a lot. I'm going to test that one, suffice to say, I'm looking to explicitly tell the browser to not wait for a request that was just made. Anything less risks the browser showing you that something is loading--even in the background. It gets you into a situation where you have to test every browser, as opposed to a fail-safe pattern. I'm definitely going for failsafe--something that doesn't look for a back-door to hide loading.
Mike Levin
A: 

As the other answer suggests, you could simply add the img tag to the image after the document loads.

This brings about two subproblems: 1) how do you know when the document is loaded and 2) how to add the img tag. I suggest using the $(document).ready() from JQuery for 1) and some DOM manipulation for 2) (also with JQuery).

There are methods of detecting when the document is completely loaded and inserting a tag, but using a framework (alternatives other than JQuery should be OK, I'm just suggesting something I know works) saves you some effort, especially when it comes to making things work on multiple browsers.

EDIT: typo

Miron Brezuleanu
Two issues: 1) I'm going for as lightweight as possible. Even JQuery with it's ridiculously small footprint for what it does is too much of a dependency. If I deploy this as a general tracking system, there's a chance people will have JQuery already included, creating potential collision issues I'd rather avoid. And the code I ask people to add to every page of their site should be not have other calls in-turn, aside to the one that sends the request with the data to record.
Mike Levin
The second issue is one I should have specified in the initial post. While I understand that images can be appended to the DOM after a page-load has completed, thereby not applying the load-time to the page-load, the load-time is still there. I don't need the image loaded, and would actually like to abort it's request, or use a model other than HTTP request/response if possible. I'm looking for an explicit and fail-safe method.
Mike Levin
A: 

You can POST with a form that target an iframe(same or different domain is ok).

And after you make the call, you can remove the iframe or reuse it.

Here is an example:

<form target="targetIfr" action="http://domain.com/" method="post">
    <input name="data" type="text" value="hello" />
</form>
<iframe name="targetIfr"></iframe>

You can call it like:

frm.submit();
ifr.parentNode.removeChild(ifr);
Mic
Nice. Because the iframe pops into existence almost instantaneously, as opposed to an img you have to wait for. And you kill the container immediately on it's existence. That's the kind of thing I'm talking about.
Mike Levin
A form submitting to a hidden iframe has the same "loading" semantics as an image with a src.
Roatin Marth
And you can place the JS commands in a script tag at the beginning of the body tag. The document is then loaded. The image load has one advantage: you can pass the parameters in the src string without javascript. Here it won't work if JS is disabled.
Mic
@mic I'm willing to use JavaScript@Roatin Interesting. If that's true, couldn't this same trick be used on an img tag? My initial thought was to detect events, but if a mere existence check is enough to remove it, couldn't I just...img id="foo" src...if getElementById... parent.removeChild(foo); ?I might wait a few milliseconds to deal with the race condition, but is the img element removable from the DOM the instant it's called?
Mike Levin
I did some tests as I need to solve almost the same problem. Loading an image by setting it's src to a query string and set immediately after src='' is ~3 times faster than posting an iframe. The only advantage of the iframe is there is no size limit.
Mic
Uhhh... investigated setting src="" and found some people saying that will cause the whole page to load again http://geekswithblogs.net/bcaraway/archive/2007/08/24/114945.aspx and show loading in the background (exactly the artifacts I keep mentioning), or that it will attempt to load the homepage html into the src tag (can't find that link). I found removing it from the DOM to be cleaner. Seems the test that remains is doing a removeChild on an img tag immediately after creating it and without event handling. This will cause a race condition, but it may be the least of all evils.
Mike Levin