JavaScript获取正确的请求

68 阅读1分钟

实现两个耗时不同的请求更改同一处,并分别执行多次,将最后一次作为最终结果

一、模拟两个耗时不同的请求

const reqa = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('A')
      }, 1000)
    })
  }
  const reqb = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('B')
      }, 3000)
    })
  }

二、两个button都可以更改div里面的内容

<body>
  <button onClick="clickA()">A</button>
  <button onClick="clickB()">B</button>
  <div id="message"></div>
</body>
<script>
  function clickA() {
    document.getElementById('message').innerHTML = 'A'
  }
  function clickB() {
    document.getElementById('message').innerHTML = 'B'
  }
</script>

三、通过模拟请求更改div里面的内容

<body>
  <div>方法一 给每个请求添加标记</div>
  <button onClick="clickA()">A</button>
  <button onClick="clickB()">B</button>
  <div id="message"></div>
</body>
<script>
  const reqa = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('A')
      }, 1000)
    })
  }
  const reqb = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('B')
      }, 3000)
    })
  }
  function clickA() {
    reqa().then(res => {
      document.getElementById('message').innerHTML = res
    })
  }
  function clickB() {
    reqb().then(res => {
      document.getElementById('message').innerHTML = res
    })
  }
</script>
// 存在一个问题 连续点击A->B->A
// 因为请求耗费时间不同 会显示 A->A->B
// 如何让内容成功显示A就是本文的重点

四、方法一 给每个请求添加标记

  var current = 0
  function clickA() {
    const idx = ++ current
    reqa().then(res => {
      if(idx == current) {
        document.getElementById('message').innerHTML = res
      }
    })
  }
  function clickB() {
    const idx = ++ current
    reqb().then(res => {
      if(idx == current) {
        document.getElementById('message').innerHTML = res
      }
    })
  }
  // 连续点击A->B->A 会显示A

五、方法二 多个请求顺序串联

  var currentPromise = Promise.resolve('i')
  function clickA() {
    currentPromise = currentPromise.then(() => reqa()).then(value => {
      document.getElementById('message').innerHTML = value
    })
  }
  function clickB() {
    currentPromise = currentPromise.then(() => reqb()).then(value => {
      document.getElementById('message').innerHTML = value
    })
  }
  // // 连续点击A->B->A 会显示A->B->A

六、方法三 取消上次请求的回调

 var lastCancel = undefined
  function cancelAble(req, callback) {
    let cb = callback
    req().then((value) => {
      cb && cb(value)
    })
    const cancel = () => {
      cb = undefined
    }
    return cancel
  }
  function clickA() {
    this.lastCancel && this.lastCancel()
    this.lastCancel = cancelAble(reqa, (value) => {
      document.getElementById('message').innerHTML = value
    })
  }
  function clickB() {
    this.lastCancel && this.lastCancel()
    this.lastCancel = cancelAble(reqb, (value) => {
      document.getElementById('message').innerHTML = value
    })
  }
  // 连续点击A->B->A 会显示A

七、完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>方法一 给每个请求添加标记</div>
  <button onClick="clickA()">A</button>
  <button onClick="clickB()">B</button>
  <div id="message"></div>
  <div>方法二 多个请求顺序串联</div>
  <button onClick="clickA1()">A1</button>
  <button onClick="clickB1()">B1</button>
  <div id="message1"></div>
  <div>方法三 取消上次请求的回调</div>
  <button onClick="clickA2()">A2</button>
  <button onClick="clickB2()">B2</button>
  <div id="message2"></div>
</body>
<script>
  // 模拟请求
  const reqa = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('A')
      }, 1000)
    })
  }
  const reqb = () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve('B')
      }, 3000)
    })
  }
  
  // 方法一
  var current = 0
  function clickA() {
    const idx = ++ current
    reqa().then(res => {
      if(idx == current) {
        document.getElementById('message').innerHTML = res
      }
    })
  }
  function clickB() {
    const idx = ++ current
    reqb().then(res => {
      if(idx == current) {
        document.getElementById('message').innerHTML = res
      }
    })
  }
  
  // 方法二
  var currentPromise = Promise.resolve('i')
  function clickA1() {
    currentPromise = currentPromise.then(() => reqa()).then(value => {
      document.getElementById('message1').innerHTML = value
    })
  }
  function clickB1() {
    currentPromise = currentPromise.then(() => reqb()).then(value => {
      document.getElementById('message1').innerHTML = value
    })
  }

  // 方法三
  var lastCancel = undefined
  function cancelAble(req, callback) {
    let cb = callback
    req().then((value) => {
      cb && cb(value)
    })
    const cancel = () => {
      cb = undefined
    }
    return cancel
  }
  function clickA2() {
    this.lastCancel && this.lastCancel()
    this.lastCancel = cancelAble(reqa, (value) => {
      document.getElementById('message2').innerHTML = value
    })
  }
  function clickB2() {
    this.lastCancel && this.lastCancel()
    this.lastCancel = cancelAble(reqb, (value) => {
      document.getElementById('message2').innerHTML = value
    })
  }
</script>
</html>