返回

一键搞定 Promise 重复回调问题

前端

Promise 回调重复调用的原因

在 JavaScript 中,Promise 是一个对象,它表示一个异步操作的最终完成或失败。当我们调用 Promise 的 then()catch() 方法时,我们指定了一个回调函数,该函数将在 Promise 完成或失败时被调用。

通常情况下,回调函数只会被调用一次。但是,在某些情况下,回调函数可能会被重复调用。例如,如果我们在用户快速点击刷新按钮后,短时间内会有多个网络请求发出,那么这些请求的回调函数可能会被重复调用。

简单粗暴地防止回调函数被重复调用

为了防止回调函数被重复调用,我们可以使用一个简单的技巧。每次我们调用 Promise 的 then()catch() 方法时,我们都保存当前的上下文环境(例如,当前时间戳)。然后,当我们接到返回的时候,我们判断一下当前的时间戳是否与保存的时间戳相同。如果不同,则说明该回调函数是由于之前的请求而被调用的,我们可以忽略它。

const makeRequest = () => {
  // 保存当前的时间戳
  const timestamp = Date.now();

  // 调用 Promise 的 then() 方法
  return fetch('https://example.com')
    .then(response => {
      // 判断当前的时间戳是否与保存的时间戳相同
      if (timestamp !== Date.now()) {
        // 如果不同,则忽略该回调函数
        return;
      }

      // 如果相同,则处理请求的返回结果
      return response.json();
    });
};

使用唯一标识来解决重复回调问题

除了使用上述技巧之外,我们还可以使用唯一标识来解决重复回调问题的。每次我们调用 Promise 的 then()catch() 方法时,我们都生成一个唯一的标识。然后,当我们接到返回的时候,我们判断一下该唯一标识是否已经存在。如果存在,则说明该回调函数是由于之前的请求而被调用的,我们可以忽略它。

const makeRequest = () => {
  // 生成一个唯一的标识
  const requestId = Math.random().toString(36).substring(7);

  // 调用 Promise 的 then() 方法
  return fetch('https://example.com')
    .then(response => {
      // 判断该唯一标识是否已经存在
      if (requestId !== requestIdMap[response.url]) {
        // 如果存在,则忽略该回调函数
        return;
      }

      // 如果不存在,则处理请求的返回结果
      return response.json();
    });
};

总结

在 JavaScript 中,Promise 回调重复调用的问题可能会导致页面刷新多次或其他意外行为。我们可以使用一种简单粗暴的方法来防止回调函数被重复调用,也可以使用唯一标识来解决该问题。