我们正在创建一个构建热图的点击跟踪应用。我正在编写一个脚本,用户可以将其插入到页面中以便跟踪工作。
它适用于元素,不需要重定向或表单提交。例如,如果我点击h1
或p
或其他任何内容,它就会完全正确。但是,如果我点击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()
,但它会使事情复杂化很多,并且相信我在不同的浏览器中调试此脚本已经是一个巨大的痛苦。
有没有人有其他想法?
答案 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)如果您的特定位存在于数据中 - 根本不执行任何操作,允许进行默认事件处理。
然而,这两种方法都可能会受到影响。