6

我们正在创建一个点击跟踪应用程序,用于构建热图。我正在编写一个脚本,用户应该将其插入到他们的页面中以进行跟踪。

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

在过去的几天里,我尝试了很多方法来做到这一点。首先,我尝试了一个普通的 AJAX 调用,因为它是一个跨域请求,我必须使用 JSONP,但同样,该 AJAX 调用在重定向之前没有时间执行。添加async: false会解决问题,但它不适用于 JSONP 请求。所以我决定添加一个标志变量,表明可以安全地继续使用重定向,并使用一个空的while循环等待它在ajax回调中变为try。但是 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()表单,但这会使事情复杂化,相信我,在不同的环境中调试这个脚本已经很痛苦了浏览器。

有没有人有任何其他想法?

4

5 回答 5

7
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;
 }
于 2012-04-24T13:19:18.647 回答
4

我会看一下这个堆栈溢出答案中提到的导航器 sendBeacon API或直接链接到这里

从网站上的描述

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

于 2019-08-29T16:38:51.980 回答
1

您可以将信息保存到 ajax 请求中的 cookie 或 localStorage 中,并使任何将发送信息的工作人员。保存到 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);
});

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

于 2012-04-24T10:18:37.820 回答
1

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

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

另一种方法是: 1)在事件数据中查找特定于您的代码的内容 2)如果它不存在 - 进行 AJAX 调用并在其回调中重新触发相同的元素,即使在同一个元素上,但这次是您的添加到偶数数据的特定位;在 AJAX 调用之后返回 false 3) 如果您的特定位存在于数据中 - 只需什么都不做,允许进行默认事件处理。

然而,这两种方法都可能会咬人。

于 2012-04-24T12:21:03.663 回答
0

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

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

让我知道这是否是这种情况。如果是,我会更详细地解释。如果我没有正确理解您的要求,则继续无用

于 2012-04-24T09:47:36.857 回答