在触摸屏上滚动会大大减慢Chrome上AJAX下载时间 [英] Scrolling on touch screen dramatically slows down AJAX download time on Chrome

查看:61
本文介绍了在触摸屏上滚动会大大减慢Chrome上AJAX下载时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到一些奇怪的行为,只要您按住手指,AJAX请求就会在用手指滚动时偶尔挂起.很难用语言来描述问题,因此请看一下这个小提琴:

I'm seeing some strange behavior where an AJAX request just hangs occationally when scrolling with the finger, as long as your finger is held down. It's hard to describe the issue in words, so take a look at this fiddle:

$("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);
     });
  }

https://jsfiddle.net/rx1qj9L5/5/

它会引发AJAX请求(向不存在的URL)并返回错误.在scroll事件上触发AJAX请求.使用鼠标滚动时,平均时间在80-200毫秒之间.这似乎很一致.

It fires an AJAX request (to a non-existant URL) and gets an error back. The AJAX request is fired on the scroll event. When you use the mouse scroll, the average time is between 80-200 ms. This seems to be very consistant.

麻烦就出在这里.用手指滚动时,ajax请求可能会卡在下载内容"中无限,直到手指从滚动中释放出来为止.

Here's where the trouble comes in. When scrolling with the finger, the ajax request can get stuck in "downloading content" INDEFINATELY until the finger is released from scrolling!

使用以下步骤,我可以一致地重现:

using the following steps, I'm able to reproduce consistantly:

  1. 在启用了触摸功能的设备上(在Google Chrome中)重新刷新上面的页面
  2. 打开chrome开发工具,转到网络"标签
  3. 在可滚动的div上向下触摸(不要松开!),同时按住手指来上下滚动.
  4. 这将触发3个ajax调用,其中第三个将无限期地挂起,直到您释放手指为止.仅当手指在Google chrome中滚动时才会发生这种情况.
  5. 松开手指的那一刻,您会看到Ajax通过.

我想不出这种现象的任何原因.有人遇到过这个吗?这个问题有解决方法吗?

I can't think of any reason for this behavior. Has anyone encountered this? Would there be any workaround to this issue?

p.s. -我尝试在香草Javascript中进行相同的绑定.没什么区别:/

p.s. - I've tried doing the same bindings in vanilla Javascript. No differences. :/

推荐答案

好的,我找到了这种现象的原因.由于JavaScript默认情况下是单线程的,因此在启用触摸的设备上滚动时,线程将暂停. (我感觉禁用事件的被动"性质应该可以解决问题,但线程 still 已暂停)

Ok, I found the reason for this behavior. Since JavaScript by default is single-threaded, while scrolling on touch-enabled devices, the thread is paused. (I feel like disabling the "passive" nature of the event should have solved the issue, but the thread is still paused)

但是,有解决方案.如果生成html5 WebWorker,则 JavaScript不再是单线程的. WebWorker拥有自己的线程,滚动不再引起任何问题.

However, there is a solution. If you spawn a html5 WebWorker, JavaScript is no longer single threaded. The WebWorker gets it's own thread, and scrolling no longer causes any issues.

在Webworker中使用Ajax进行一些我自己的测试时,Ajax始终保持更快的速度,并且在滚动时也可以完美地工作.这是我见过的最流畅的无限滚动!

Doing some of my own tests with ajax in a webworker, the ajax is consistently faster, and it works flawlessly with scrolling. It's the smoothest infinite scroll I've ever seen!

通过Webworker进行的Ajax似乎在所有情况下都能更好地工作(可能是因为它获得了自己的专用线程?),但尤其用于移动chrome,在此期间,暂停了滚动,并在滚动后 保持1-2秒暂停.使用Web Worker可以使Ajax在滚动甚至停止之前就完成,因此它给人无限期无缝滚动的错觉.

The ajax through the webworker seems to work better all around (probably because it gets it's own dedicated thread?) but especially for mobile chrome, where ajax is paused during scrolling, and continues to be held for a 1-2 second pause after the scrolling. Using the web worker allows the ajax to complete before the scrolling even stops, and so it gives the illusion of seamless scrolling indefinitely.

这是我的(与依赖无关的)解决方案,用于通过网络工作者调用ajax函数:

Here's my (dependant free) solution for calling an ajax function with a web worker:

// wajax (webworker ajax)
function wajax(obj)
{

  var sendObj = {};

  sendObj.url  = obj.url;
  sendObj.data = obj.data;
  sendObj.csrf = {{csrfToken here}}; //make sure to fill this out if you're using csrf tokens


  if (typeof(Worker) !== "undefined") {
    if (typeof(ajaxWorker) === "undefined") {
      ajaxWorker = new Worker("path/to/webworker.js");
    }


    ajaxWorker.postMessage(JSON.stringify(sendObj));

    ajaxWorker.onmessage = function(event) {
      obj.success(event.data);
    };
  }
  else {
    // This means webworkers aren't available. Here, just do a regular ajax call....
  }
}

Webworker(与页面javascript分开的脚本/线程):

Webworker具有我从jQuery源代码派生的代码,以允许在AJAX调用中使用JSON对象.我将源代码精简到最低限度.在缩小之前,webworker的完整大小只有80行左右.

Webworker (separate script / thread from the page's javascript):

The webworker has code I derived from the jQuery source code to allow JSON objects to be used in AJAX calls. I stripped down the source code to the bare minimum. Full size of webworker is only around 80 lines before minifying.

/* 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));

};

一旦完成,您可以像这样发出ajax请求:

Once this is in place, you can just make an ajax request like so:

wajax({
  url    : "/some/url",
  data   : {value_a:"somestuff",value_b:2},
  success: function(response) {
    // do something with the response
  }
});

随时使用和修改此代码.

Feel free to use and adapt this code.

这篇关于在触摸屏上滚动会大大减慢Chrome上AJAX下载时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆