0

I'm currently facing a situation similar to the relatively-simple example shown below. When a user clicks on a link to a third-party domain, I need to capture certain characteristics present in the user's DOM and store that data on my server. It's critical that I capture this data for all JS-enabled users, with zero data loss.

I'm slightly concerned that my current implementation (shown below) may be problematic. What would happen if the external destination server was extremely fast (or my internal /save-outbound-link-data endpoint was extremely slow), and the user's request to visit the external link was processed before the internal AJAX request had enough time to complete? I don't think this would be a problem (because in this situation, the browser doesn't care about receiving a response from the AJAX request), but getting some confirmation from fellow developers would be much appreciated.

Also, would the answer to the question above vary if the <a> link pointed to an internal URL rather than an external one?

<script type="text/javascript">
    $(document).ready(function() {
        $('.record-outbound-click').on('click', function(event) {
            var link = $(this);
            $.post(
                '/save-outbound-link-data',
                {
                    destination: link.attr('href'),
                    category:    link.data('cat')
                },
                function() {
                    // Link tracked successfully.
                }
            );
        });
    });
</script>
<a href="http://www.stackoverflow.com" class="record-outbound-click" data-cat="programming">
    Visit Stack Overflow
</a>

Please note that using event.preventDefault(), along with window.location.href = var.attr('href') inside $.post's success callback, isn't a viable solution for me. Neither is sending the user to a preliminary script on my server (for instance, /outbound?cat=programming&dest=http://www.stackoverflow.com), capturing their data, and then redirecting them to their destination.

Nate
  • 1,442
  • 14
  • 22
  • 2
    Why are the two approaches you outline at the end of your post not viable? The first of the two of them strikes me as the standard approach here. – Brendan W Aug 03 '15 at 23:24
  • Thanks for the response, @brendan. The example code I posted here is pretty contrived. In reality, I'm working within the limitations of more complicated legacy code that can't be modified to take advantage of either of those alternative approaches. – Nate Aug 03 '15 at 23:28
  • 1
    @NateB, what limitations specifically is the legacy code imposing? Hard to imagine that it's restricting you so much that you can't stop the link from going anywhere and just redirect in a callback. Also, why can't the legacy code be modified? And you're right, depending on the `POST` to complete before a location change is a bad idea. Sort of a race-condition type of scenario. – Josh Beam Aug 03 '15 at 23:40
  • @JoshBeam, you're right -- the legacy code *could* technically be updated. More broadly, though, I was hoping to understand from a theoretical point of view whether or not the risk I'm concerned about is a legitimate one. I understand that the alternate approaches are the preferred ones, but for the sake of argument (and for others who may truly be in a position similar to this one) let's assume that they're off the table. – Nate Aug 03 '15 at 23:40

1 Answers1

2

Edit 2

Also consider the handshake step (Google's docs):

Time it took to establish a connection, including TCP handshakes/retries and negotiating a SSL.

I don't think you and the server you're sending the AJAX request to can complete the handshake if your client is no longer open for connection to the server (i.e., you're already at Stackoverflow or whatever website your link navigates to.)

Edit 1

More broadly, though, I was hoping to understand from a theoretical point of view whether or not the risk I'm concerned about is a legitimate one.

That's an interesting question, and the answer may not be as obvious as it seems.

enter image description here

That's just a sample request/response in my network tab. Definitely shouldn't be thought of to be used as any sort of trend or representation for general requests/responses.

I think the gap we might be most concerned with is the 1.933ms stall time. There's also other additional steps that need to happen before the actual request is sent (which itself was about 0.061ms).

I'd be worried if there's an interruption in any of the 3 steps leading up to the actual request (which took about 35ms give or take).

I think the question is, if you go somewhere else before the "stalled", "DNS Lookup", and "Initial connection" steps happen, is the request still going to be sent? That part, I don't know. But what about any general computer or browser lag beforehand?

Like you mentioned, the idea that somehow the req/res cycle to/from Stackoverflow would be faster than what's happening on your client (i.e., the initiation itself -- not even the complete cycle -- of a network request to your server) is probably a bit ridiculous, but I think theoretically (as you mentioned, this is what you're interested in), it's probably a bad idea in general to depend on these types of race conditions.

Original answer

What about making the AJAX request synchronous?

$.ajax({
    type: "POST",
    url: url,
    async: false
});

This is generally a terrible idea, but if, in your case, the legacy code is so limiting that you have no way to modify it and this is your last option (think, zombie apocalypse), then consider it.

See jQuery: Performing synchronous AJAX requests.

The reason it's a bad idea is because it's completely blocking (in normal circumstances, you don't want potentially un-completeable requests blocking your main thread). But in your case, it looks like that's actually exactly what you want.

Community
  • 1
  • 1
Josh Beam
  • 19,292
  • 3
  • 45
  • 68
  • Thanks, Josh. I replied to your comment above. In general, I was hoping to get a better understanding of the potential race conditions that may exist in my code sample, rather than seeking a solution to remove the problem entirely. – Nate Aug 03 '15 at 23:46
  • @NateB, a totally reasonable question. I'm curious to find out more about this myself. I updated my answer anyhow, hopefully it can provide some extra info. – Josh Beam Aug 03 '15 at 23:52