在重定向之前将有关已点击链接的信息发送到服务器

时间:2012-04-24 09:39:45

标签: javascript jquery

我们正在创建一个构建热图的点击跟踪应用。我正在编写一个脚本,用户可以将其插入到页面中以便跟踪工作。

它适用于元素,不需要重定向或表单提交。例如,如果我点击h1p或其他任何内容,它就会完全正确。但是,如果我点击a,对我们的服务器的请求永远不会发生在正常重定向之前。

在过去的几天里,我尝试了很多方法来做到这一点。首先,我尝试了一个普通的AJAX调用,因为它是一个跨域请求,我不得不使用JSONP,但同样,AJAX调用在重定向之前没有时间执行。添加async: false可以解决问题,但它不适用于JSONP请求。所以我决定添加一个标志变量,表示使用重定向继续运行是安全的,并使用空的while循环等待它在ajax回调中尝试。但是while循环阻止了执行流程,因此回调从未有机会将该变量设置为true。这是一些简化的代码:

$(document).on('click', function (e) {
    //part of the code is omitted 
    $.ajax({
        url: baseUrl,
        data: data,
        type: "get",
        dataType: "jsonp",
        crossDomain: true,
        complete: function (xhr, status,) {
            itsSafeToMoveOn = true;
        }
    });

    while(!itsSafeToMoveOn){}

    return true;
});

我尝试的下一件事是使用unload页面事件等待,直到正在进行的总ajax调用变为零(我实现了一个计数器),然后继续进行重定向。它在Firefox和IE中有效,但在WebKit中出现了这个错误:

Error: Too much time spent in unload handler

之后我意识到我并不关心服务器响应,并且使用img.src请求将是这种情况的理想选择。所以在这一点上代码看起来像这样:

$(document).click(function (e) {
    //part of the code is ommited
    (new Image).src = baseUrl + '?' + data;

    if (tag === "a" || clickedElement.parents().has("a")) {
        sleep(100); 
    }

    return true;
});

这样我略微提高了整体脚本性能,但链接问题仍未改变。 sleep函数似乎也阻止了执行流程,请求永远不会发生。

唯一的想法是从事件处理程序返回false,然后手动重定向到单击元素的href或在表单上调用submit(),但它会使事情复杂化很多,并且相信我在不同的浏览器中调试此脚本已经是一个巨大的痛苦。

有没有人有其他想法?

5 个答案:

答案 0 :(得分:6)

var globalStopper = true;

$(document).on('click', function (e) {
    if (globalStopper === false)
        return true; //proceed with click if stopper is NOT set
    else {
        globalStopper = false; //release the breaks

        $.ajax({
            //blahblah
            complete: function (xhr, status,) {
                $(elem).click(); //when ajax request done - "rerun" the click
            }
        });
        return false; //DO NOT let browser process the click
    }
});

此外,尝试添加脚本,而不是添加图像。然后将脚本添加到HEAD部分。这样浏览器将“等待”直到它被加载。

 $(document).on('click', function (e) {
     var scriptTag = document.createElement("script");
     scriptTag.setAttribute("type", "text/javascript");
     scriptTag.setAttribute("src", url);
     document.getElementsByTagName("head")[0].appendChild(scriptTag);
     return true;
 }

答案 1 :(得分:1)

我来看看this stack overflow answer中提到的导航器sendBeacon API或直接链接到here的浏览器。

根据网站上的说明

  

navigator.sendBeacon(URL,data)-此方法解决了分析和诊断代码的需求,这些代码通常尝试在卸载文档之前将数据发送到Web服务器。

答案 2 :(得分:0)

因此,如果我理解正确,您希望在页面卸载之前完成ajax日志并遵循链接href。这听起来像是一个完美的案例,您可以考虑在jQuery中使用Deferreds

当您的用户点击任何应该将他带离页面的内容时,只需检查您的promise状态。如果它没有解决,你可以在页面上抛出一个模态窗口,并要求用户等待进度完成。然后,向pipe添加一个新的deferred,告诉它在所有内容完成后更改location href

如果是这种情况,请告诉我。如果是,我会更详细地解释。如果我不理解您的要求,请继续使用

答案 3 :(得分:0)

您可以将信息保存到cookie或localStorage中的ajax请求中,并使任何将发送信息的工作人员。保存到cookie或localStorage比ajax-request更快。你可以做下一个:

$(document).click(function (e) {
    var queue = localStorage.getItem('requestQueue');
    queue.push(data);
    localStorage.setItem('requestQueue',queue);
});

$(function(){
  setInterval(function(){
    var queue = localStorage.getItem('requestQueue');
    while (queue.length > 0) {
      var data = queue.pop();
      $.ajax({
        ...
        success: function(){
          localStorage.setItem('requestQueue', queue);
        }
      });
    }
  },intervalToSendData);
});

因此,当用户点击链接或发送表单时,数据将保存到存储中,在用户转到下一页后,该工作人员将启动数据并将数据发送到您的服务器。

答案 4 :(得分:0)

JavaScript基本上是在单线程中执行的。执行回调函数是不可能的,同时有一个无限循环等待它的标志变量。无限循环将占用单个执行线程,并且永远不会调用回调。

最佳方法是取消事件的默认处理程序并为其冒泡(如果您真的使用jQuery构建跟踪代码,则基本上返回false),并执行必要的操作(如果链接是,则将页面重定向到必要的地址单击或触发其他默认操作),但这需要花费大量精力来重新创建动作和回调的所有可能组合。

另一种方法是: 1)在事件数据中查找特定于您的代码的内容 2)如果它不存在 - 进行AJAX调用并在其回调中重新触发相同的元素,但这次将您的特定位添加到偶数数据; AJAX调用后返回false 3)如果您的特定位存在于数据中 - 根本不执行任何操作,允许进行默认事件处理。

然而,这两种方法都可能会受到影响。