搜索页面 input框onChange的时候调接口模糊搜索 请求相应速度不同引起了渲染数据是后返回数据的请求结果 有什么好的解决方案吗?

例如:第一次输入'如何',后端返回给我标题带有'如何'的文章数据,页面渲染'如何'相关文章
继续输入'准备',后端返回给我标题带有'如何准备'的文章数据,页面渲染'如何准备'相关文章
引发了一个问题 因为后端接口查'如何准备'返回的数据更快 导致页面先渲染'如何准备'相关文章然后又快速渲染'如何'相关文章 几乎看不到'如何准备'相关文章 感觉就像是搜索'如何准备'
页面渲染的是'如何'相关文章 请问这种问题 有什么好的解决方案吗?

阅读 3.7k
3 个回答

防抖是防抖,但防抖不是为了解决这个时序问题的,它只是为了避免“输一个字符就发起一个请求”这种问题的。


正确的做法是全局存储一个 key,请求前生成一个唯一值、并利用闭包的特性获取其一份副本,然后请求结束后时比较副本和全局存储的 key,如果不相等,说明后面又有新的请求了,那就丢掉本次响应。

伪代码:

let loadingKey = 0;

const request = () => {
  loadingKey++;
  const currentKey = loadingKey;
  return axios.request({ /* 请求参数略 */ })
    .then((res) => {
      if (currentKey !== loadingKey) {
        return; // 丢弃响应
      }

      console.log(res); // todo
    });
}

Promise.all([
  request(),
  request(),
  request() // 只有最后发出的请求的响应会被保留,前面的即使响应时序是后回来的,也会被丢弃
]);

大名鼎鼎的 ahooks 库的 useRequest 就是这样实现的,当然它那个里面还有很多别的功能,所以代码看起来很复杂,但抽丝剥茧背后的原理是一样的。它是全局持有了一个 count 对象,每次 runAsync 之前 +1 然后持有了一个副本 currentCount。跟这里的 loadingKeycurrentKey 是一回事儿。


当然你也可以配合 axios 的 CancelToken 来实现,但这个方案跟 axios 就耦合过深了,以后换库就不太好办。

常规的办法是做一下防抖(Debounce)你可以设置一个300毫秒的防抖时间,这样在用户连续输入时候,用户输入完之后300毫秒后才会发送请求。

可以考虑给页面加一个loading效果,只有当loading结束的时候才去请求下一个

推荐问题