XHR / setTimeout / Promise直到滚动停止在Chrome中才完成

时间:2016-01-26 21:26:29

标签: javascript google-chrome scroll xmlhttprequest settimeout

在Chrome中,如果用户正在滚动所有XHR并且setTimeouts将延迟,直到滚动停止,我需要一个解决方法。 this blog post中描述了该行为。虽然这个功能有助于移动滚动,但对于无限滚动来说却是灾难性的,这正是我试图做的。

发生这种情况的证据:

  • 所有其他浏览器都能正常运行,Chrome会在用户停止滚动之前显示空白屏幕。

  • 网络面板会将所有请求显示为pending,直到滚动结束,然后它们全部完成。

  • 将它放在一个片段中,运行它然后立即开始滚动。滚动完成后才会调用setTimeout。

var p = new Promise(function (resolve) {
    setTimeout(function () {
        console.log('resolving');
        resolve();
    }, 1000)
});

p.then(function () {
    console.log('DONE!!');
})

4 个答案:

答案 0 :(得分:6)

根据您的具体情况和所需的浏览器支持,我会尝试使用Service Workers - 这些任务适用于您正在处理的任务(并且可以拦截所有流量),或者在后台Web Workerdo your AJAX

答案 1 :(得分:1)

由于这与引擎有关,我认为没有可行的解决方法。相反,我已向Chrome小组提交了错误报告。

https://bugs.chromium.org/p/chromium/issues/detail?id=661155

答案 2 :(得分:1)

我认为这可能与此Chrome功能有关:

https://www.chromestatus.com/feature/5745543795965952(被动事件监听器)

当用户滚动时,Chrome会尝试避免在移动设备上进行操作,因此,有时会收听touchmove事件会延迟处理程序的运行以及触发超时。

演示:
https://rbyers.github.io/scroll-latency.html
(检查Handler Jank并滚动页面)

答案 3 :(得分:0)

我遇到了无限滚动和图像砌筑的相同问题,最后能够“强制”使用铬来停止通过模拟文档点击来减少对更多图像的请求。我知道这听起来很奇怪,但是当我测试时,只要我滚动,请求就会无限制地去抖动,但只要我点击一次,它就会立即执行XHR。

我是这样做的......:

export function getPosts() {
  return (dispatch: Dispatch<any>, getState) => {
    const { postFeedState }: IGlobalState = getState();

    dispatch(handlePostsCancellation())

    dispatch({ type: postFeedTypes.GET_POSTS_REQUEST });

    const feedFilterDto = getFeedFilterDto(getState);

    // this is where the clicks are simulated  
    setTimeout(() => {
      for (let i = 0; i < 3; i++) {
        const evt = document.createEvent("Events");
        evt.initEvent("click", true, true);
        window.dispatchEvent(evt);
      }
    }, 50);

    return dispatch(setCancelSource(postFeedTypes.SET_MAIN_FEED_POSTS_CANCEL_SOURCE))
      .then((source) => PostController.getMainFeedPosts(postFeedState.get("postsToSkip"), FeedDisplay.THREE_COLUMNS, feedFilterDto, source))
      .then(posts => dispatch(getPostsSuccess(posts)))
      .catch(error => {
        if (axios.isCancel(error)) return;

        dispatch({ type: postFeedTypes.GET_POSTS_FAILURE });

        dispatch(handleApiError(error, null));
      });
  }
}

我首先尝试只点击一次,它几乎一直工作,然后尝试2-3次点击并一直工作。说实话,我仍然对这个超时/点击代码感到有些奇怪,但是什么都有效,有效!此外,时间将证明这是否会继续有效,但目前这是我发现的最佳解决方案和最简单的解决方案。

P.S:我使用redux和axios并为我的端点(PostController)拥有自己的自定义类,但它只是一个axios(XHR)请求。