Javascript 触摸屏上的滚动大大降低了在Chrome上下载AJAX的速度
我看到一些奇怪的行为,当用手指滚动时,只要按住手指,AJAX请求就会偶尔挂起。很难用语言来描述这个问题,所以看看这把小提琴:Javascript 触摸屏上的滚动大大降低了在Chrome上下载AJAX的速度,javascript,jquery,ajax,google-chrome,Javascript,Jquery,Ajax,Google Chrome,我看到一些奇怪的行为,当用手指滚动时,只要按住手指,AJAX请求就会偶尔挂起。很难用语言来描述这个问题,所以看看这把小提琴: $("div").on('scroll', infiniteDictionaryScrollAjax); function infiniteDictionaryScrollAjax(){ $("div").off("scroll"); $.ajax({ type: "POST", url : "/someURL", data:
$("div").on('scroll', infiniteDictionaryScrollAjax);
function infiniteDictionaryScrollAjax(){
$("div").off("scroll");
$.ajax({
type: "POST",
url : "/someURL",
data: {data: "data"}
})
.done(function(response) {
$("div").append("<br>appendedData");
$("div").on('scroll', infiniteDictionaryScrollAjax);
})
.fail(function() {
$("div").append("<br>appendedError");
$("div").on('scroll', infiniteDictionaryScrollAjax);
});
}
它向不存在的URL发出AJAX请求并返回错误。AJAX请求在scroll事件中触发。使用鼠标滚动时,平均时间在80-200毫秒之间。这似乎非常一致
麻烦就在这里。当用手指滚动时,ajax请求可能会陷入无法确定的下载内容中,直到手指从滚动中释放出来
通过以下步骤,我能够始终如一地复制:
在谷歌Chrome的触控设备上重新加载上面的页面
打开chrome开发工具,转到网络选项卡
触摸可滚动的div,不要放手!按住手指上下滚动。
这将触发3个ajax调用,第三个调用将无限挂起,直到您松开手指为止。只有在谷歌浏览器中用手指滚动时才会发生这种情况。
在您松开手指的那一刻,您将看到Ajax已经完成。
我想不出这种行为的任何原因。有人遇到过这种情况吗?这个问题有什么解决办法吗
p、 我试过用香草Javascript做同样的绑定。没有区别/
我想不出这种行为的任何原因
这很可能是为了减少用户滚动时运行的JavaScript量,从而使滚动更加平滑。当JavaScript运行时,它会阻止UI更新,这可能会导致一些不方便的滚动,特别是在有一些严重的DOM操作的情况下
有人遇到过这种情况吗
我发现有人提交了一个铬问题,听起来像是同一个问题:。看起来它关闭了,因为不确定是否存在
这个问题有什么解决办法吗
可能不会
我想不出这种行为的任何原因
这很可能是为了减少用户滚动时运行的JavaScript量,从而使滚动更加平滑。当JavaScript运行时,它会阻止UI更新,这可能会导致一些不方便的滚动,特别是在有一些严重的DOM操作的情况下
有人遇到过这种情况吗
我发现有人提交了一个铬问题,听起来像是同一个问题:。看起来它关闭了,因为不确定是否存在
这个问题有什么解决办法吗
可能不会。当用户位于页面底部时,您需要触发ajax
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
$.ajax({
type: "POST",
url : "/someURL",
data: {data: "data"}
})
.done(function(response) {
$("div").append("<br>appendedData");
})
.fail(function() {
$("div").append("<br>appendedError");
});
}
});
当用户位于页面底部时,需要触发ajax
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
$.ajax({
type: "POST",
url : "/someURL",
data: {data: "data"}
})
.done(function(response) {
$("div").append("<br>appendedData");
})
.fail(function() {
$("div").append("<br>appendedError");
});
}
});
这可能值得研究: 使用被动事件侦听器提高滚动性能 当你滚动一个页面时,会出现这样的延迟,以至于页面感觉不到固定在你的手指上,这就是所谓的滚动jank。很多时候,当你遇到scroll jank时,罪魁祸首是一个触摸事件监听器。对于Chrome51来说,被动事件监听器是一种新兴的网络标准,它可以极大地提高滚动性能,尤其是在移动设备上
这可能值得研究: 使用被动事件侦听器提高滚动性能 当你滚动一个页面时,会出现这样的延迟,以至于页面感觉不到固定在你的手指上,这就是所谓的滚动jank。很多时候,当你遇到scroll jank时,罪魁祸首是一个触摸事件监听器。对于Chrome51来说,被动事件监听器是一种新兴的网络标准,它可以极大地提高滚动性能,尤其是在移动设备上
该行为取决于您的机器。由于您频繁地进行AJAX调用,您正在耗尽系统资源。这对于使用低端设备的移动用户来说尤其令人讨厌 在我的笔记本电脑上,每次我滚动时都会触发AJAX请求。但是,我很快就收到了以下违规行为: [冲突]执行JavaScript时强制回流 这是因为您经常修改DOM。请参阅关于强制布局/回流和布局抖动的说明 相反,您要做的是限制您正在为每个滚动处理的代码。您可以通过取消函数的抖动(也称为限制函数的执行速率)来实现这一点 您可以导入一个库,比如,它有这样的功能,但是如果这是您唯一需要它的地方,那么这可能太过分了。幸运的是,编写我们自己的基本去盎司函数相对来说比较轻松:
function debounce(func, timeToWait) {
var timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(func, timeToWait);
};
}
针对您的问题,您可以使用debounce来限制infiniteDictionaryScrollAjax的执行率:
看到一个正在工作的人。请注意,AJAX调用在用户暂停滚动后仅运行500毫秒,这对于移动设备来说是完全合理的,因为用户将短暂暂停以查看cont
当他们滚动的时候,他们会发出声音 行为取决于您的机器。由于您频繁地进行AJAX调用,您正在耗尽系统资源。这对于使用低端设备的移动用户来说尤其令人讨厌 在我的笔记本电脑上,每次我滚动时都会触发AJAX请求。但是,我很快就收到了以下违规行为: [冲突]执行JavaScript时强制回流 这是因为您经常修改DOM。请参阅关于强制布局/回流和布局抖动的说明 相反,您要做的是限制您正在为每个滚动处理的代码。您可以通过取消函数的抖动(也称为限制函数的执行速率)来实现这一点 您可以导入一个库,比如,它有这样的功能,但是如果这是您唯一需要它的地方,那么这可能太过分了。幸运的是,编写我们自己的基本去盎司函数相对来说比较轻松:
function debounce(func, timeToWait) {
var timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(func, timeToWait);
};
}
针对您的问题,您可以使用debounce来限制infiniteDictionaryScrollAjax的执行率:
看到一个正在工作的人。请注意,AJAX调用仅在用户暂停滚动500毫秒后运行,这对于移动设备来说是完全合理的,因为用户在滚动时会短暂暂停以查看内容 好的,我找到了这种行为的原因。由于默认情况下JavaScript是单线程的,当在支持触摸的设备上滚动时,线程会暂停。我觉得禁用事件的被动性质应该可以解决问题,但线程仍然暂停 然而,有一个解决办法。如果你产生了一个HTML5WebWorker,JavaScript就不再是单线程的。WebWorker拥有自己的线程,滚动不再引起任何问题 在webworker中使用ajax进行一些我自己的测试时,ajax始终更快,并且可以完美地使用滚动。这是我见过的最平滑的无限卷轴 通过webworker的ajax似乎在各个方面都运行得更好,可能是因为它有自己的专用线程?但特别是对于移动chrome,ajax在滚动期间暂停,并在滚动后继续保持1-2秒的暂停。使用web worker允许ajax在滚动停止之前完成,因此它产生了无限期无缝滚动的错觉 以下是我的无依赖解决方案,用于使用web worker调用ajax函数: 主页js中的函数: Webworker将脚本/线程与页面的javascript分开: webworker有我从jQuery源代码派生的代码,允许在AJAX调用中使用JSON对象。我把源代码精简到最低限度。在缩小之前,webworker的完整尺寸仅为80行左右
/* ADAPTED FROM JQUERY SOURCE */
function param(a)
{
var prefix,
params = [],
add = function(key, value) {
params[params.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
};
for (prefix in a) {
buildParams(prefix, a[prefix], add);
}
// Return the resulting serialization
return params.join("&");
}
function buildParams(mainKey, mainValue, add)
{
var name;
var length = mainValue.length;
if (Array.isArray(mainValue)) {
for (var index = 0; index < length; index++) {
var value = mainKey[index];
if (/\[]$/.test(mainKey)) {
add(mainKey, value);
}
else {
buildParams(mainKey + "[" + (typeof value === "object" && value != null ? index : "") + "]", value, add);
}
}
}
else if (typeof mainValue === "object") {
for (name in mainValue) {
buildParams(mainKey + "[" + name + "]", mainValue[name], add);
}
}
else {
add(mainKey, mainValue);
}
}
/* END CODE ADAPTED FROM JQUERY SOURCE */
/*
* Created by Skeets 2017-12-13
* */
onmessage = function(e) {
var obj = JSON.parse(e.data);
obj.data._token = obj.csrf;
var request = new XMLHttpRequest();
request.open('POST', obj.url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success
var output;
try {
output = JSON.parse(request.responseText);
}
catch (e) {
output = request.responseText;
}
postMessage(output);
}
else {
// error
console.log(request.responseText);
}
};
request.onerror = function() {
// connection error
};
request.send(param(obj.data));
};
请随意使用和修改此代码。好的,我找到了这种行为的原因。由于默认情况下JavaScript是单线程的,当在支持触摸的设备上滚动时,线程会暂停。我觉得禁用事件的被动性质应该可以解决问题,但线程仍然暂停 然而,有一个解决办法。如果你产生了一个HTML5WebWorker,JavaScript就不再是单线程的。WebWorker拥有自己的线程,滚动不再引起任何问题 在webworker中使用ajax进行一些我自己的测试时,ajax始终更快,并且可以完美地使用滚动。这是我见过的最平滑的无限卷轴 通过webworker的ajax似乎在各个方面都运行得更好,可能是因为它有自己的专用线程?但特别是对于移动chrome,ajax在滚动期间暂停,并在滚动后继续保持1-2秒的暂停。使用web worker允许ajax在滚动停止之前完成,因此它产生了无限期无缝滚动的错觉 以下是我的无依赖解决方案,用于使用web worker调用ajax函数: 主页js中的函数: Webworker将脚本/线程与页面的javascript分开: webworker有我从jQuery源代码派生的代码,允许在AJAX调用中使用JSON对象。我把源代码精简到最低限度。在缩小之前,webworker的完整尺寸仅为80行左右
/* ADAPTED FROM JQUERY SOURCE */
function param(a)
{
var prefix,
params = [],
add = function(key, value) {
params[params.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
};
for (prefix in a) {
buildParams(prefix, a[prefix], add);
}
// Return the resulting serialization
return params.join("&");
}
function buildParams(mainKey, mainValue, add)
{
var name;
var length = mainValue.length;
if (Array.isArray(mainValue)) {
for (var index = 0; index < length; index++) {
var value = mainKey[index];
if (/\[]$/.test(mainKey)) {
add(mainKey, value);
}
else {
buildParams(mainKey + "[" + (typeof value === "object" && value != null ? index : "") + "]", value, add);
}
}
}
else if (typeof mainValue === "object") {
for (name in mainValue) {
buildParams(mainKey + "[" + name + "]", mainValue[name], add);
}
}
else {
add(mainKey, mainValue);
}
}
/* END CODE ADAPTED FROM JQUERY SOURCE */
/*
* Created by Skeets 2017-12-13
* */
onmessage = function(e) {
var obj = JSON.parse(e.data);
obj.data._token = obj.csrf;
var request = new XMLHttpRequest();
request.open('POST', obj.url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success
var output;
try {
output = JSON.parse(request.responseText);
}
catch (e) {
output = request.responseText;
}
postMessage(output);
}
else {
// error
console.log(request.responseText);
}
};
request.onerror = function() {
// connection error
};
request.send(param(obj.data));
};
请随意使用和调整此代码。在滚动事件上使用ajaxing是一个糟糕的选择idea@madalinivascu好吧,那么facebook是如何做到的呢?还是谷歌+?或任何其他具有无限滚动的页面?它检查用户是否已到达页面底部,然后触发ajax@madalinivascu是的,就是这个主意。这里的代码被缩减到最低限度,以表达问题的性质。另外,如果语句不能解决问题,我希望它能解决,它只会使错误更难再现五分之一,而不是每次对滚动事件进行调整都是一个糟糕的错误idea@madalinivascu好吧,那么facebook是如何做到的呢?还是谷歌+?或者任何其他具有无限滚动的页面?它检查用户是否已到达t的底部
然后触发ajax@madalinivascu是的,就是这个主意。这里的代码被缩减到最低限度,以表达问题的性质。补充说,如果语句不能解决问题,我希望它能解决,它只会使错误更难再现五分之一,而不是每次我都可以使用以下确切的代码再现错误:当ajax请求无法无限期地下载内容时,您能提供xhr请求的屏幕截图吗?触摸事件不应该与ajax请求,从屏幕截图中我可以看到你的请求转到404,你能公布你请求的时间吗?通常,在触发ajax后,您会移除手指。您的实现应该执行类似于在移动设备中刷新页面的操作,您可以向下滑动,然后释放页面进行刷新。在您的情况下,可以从ajax中附加html,如果您不释放点击,页面不会刷新。我可以使用以下代码重现错误:当ajax请求无法无限期下载内容时,您能否提供xhr请求的屏幕截图?触摸事件不应与ajax请求交互,从屏幕截图中我可以看到您的请求转到404,你能公布你请求的时间吗?通常,在触发ajax后,您会移除手指。您的实现应该执行类似于您在移动设备中刷新页面的操作,您可以向下滑动,然后释放页面以刷新页面。在您的情况下,从ajax中附加html,如果您不释放点击,则页面不会刷新这听起来很有希望,但不幸的是,将事件设置为非被动事件默认设置为被动事件并没有解决问题:/这听起来很有希望,但不幸的是,将事件设置为非被动事件默认设置为被动事件并没有解决问题:/我投赞成票,因为通过阅读,这可能是答案。不幸的是,问题似乎出在其他地方。这个请求是一个ajax请求,它不会以任何方式压倒系统,它在下载内容阶段不确定地挂起,要下载的内容只有10KB左右,我一把手指从屏幕上拿开,它就通过了。上面的代码是在我的机器上重现问题所需的最低限度。我投票赞成,因为通过阅读,它可能是答案。不幸的是,问题似乎出在其他地方。这个请求是一个ajax请求,它不会以任何方式压倒系统,它在下载内容阶段不确定地挂起,要下载的内容只有10KB左右,我一把手指从屏幕上拿开,它就通过了。上面的代码是在我的机器上重现问题所需的最低限度。您报告的这个问题也出现在桌面上,如果您向下滚动并保持鼠标滚动按钮上下移动,ajax就会被卡住,只要您继续这样做,另外,如果您只是非常快速地向下滚动,那么每3-4次ajax调用就会被卡住2-5秒,并中断平滑滚动。在第一次实现时,您是否注意到桌面上出现了这种情况?我无法在我的系统上复制它,但如果Mac桌面上出现类似问题,如果浏览器中出现平滑滚动,我也不会感到惊讶,因为我对Mac桌面不太熟悉。然而,在这里使用webworker绝对是正确的答案。无论是台式机、移动设备还是其他设备,它的运行都会更加顺畅。你的无限滚动得到它自己的不间断线程。我测试过苹果、安卓、windows、低端设备和所有主要浏览器。每次运行都更平稳。另外,其他答案被否决的唯一原因是因为我否决了它们P@nikocraft好的,我已经编辑了我的答案,包括完整的代码示例。没有库依赖性,所以它应该适合您。只是为了确认我让web worker使用vuejs,现在我获得了平滑的几乎即时无限滚动,太棒了!感谢Skeets发表这篇文章,我甚至没有意识到这件事会成为一个问题,为此我挠头了好几天。不,你不是疯了,我想我和我的编码合作伙伴疯了,我想知道世界上怎么没有人碰到这个问题,我很高兴你7个月前就这样做并发表了相关文章!:您报告的这个问题也出现在桌面上,如果您向下滚动并保持鼠标滚动按钮上下移动,ajax就会被卡住,只要您一直这样做,如果您只是非常快速地向下滚动,每3-4次ajax调用就会被卡住2-5秒,并中断平滑滚动。在第一次实现时,您是否注意到桌面上出现了这种情况?我无法在我的系统上复制它,但如果Mac桌面上出现类似问题,如果浏览器中出现平滑滚动,我也不会感到惊讶,因为我对Mac桌面不太熟悉。然而,在这里使用webworker绝对是正确的答案。无论是台式机、移动设备还是其他设备,它的运行都会更加顺畅。你的无限滚动得到它自己的不间断线程。我测试过苹果、安卓、windows、低端设备和所有主要浏览器。跑步
每一次都是驼背。另外,其他答案被否决的唯一原因是因为我否决了它们P@nikocraft好的,我已经编辑了我的答案,包括完整的代码示例。没有库依赖性,所以它应该适合您。只是为了确认我让web worker使用vuejs,现在我获得了平滑的几乎即时无限滚动,太棒了!感谢Skeets发表这篇文章,我甚至没有意识到这件事会成为一个问题,为此我挠头了好几天。不,你不是疯了,我想我和我的编码合作伙伴疯了,我想知道世界上怎么没有人碰到这个问题,我很高兴你7个月前就这样做并发表了相关文章!: