Saber2pr's Blog

解决Promise竞态问题

如果多个 promise 对同一个对象做写入操作的话,就会产生竞争,到底最终该写入谁的结果。

默认情况会按照先来后到进行多次写入。

但是有时候只想要最快响应的结果,忽略掉后续。那么可以使用 Promise.race,但这并不是很方便,因为这需要提前知道 promise 数组,如果是非同步的 promises 就没法用了(比如点击按钮发一次 promise 请求)。

所以可以利用锁机制,一个待写入资源对应一把锁,在发请求前设置 lock:true,第一次写入后设置 lock:false 阻止后续写入。

race 实现如下:

const race = (promise, then, id = "default") => {
  const locks = race.locks || {}
  locks[id] = true
  race.locks = locks
  promise.then(value => {
    if (locks[id]) {
      then(value)
      locks[id] = false
    }
  })
}

一个 id 对应一个待写入资源,多个 promise 共用一个 id,例如:

const App = () => {
  const ref = useRef()
  return (
    <div>
      <nav>
        <button
          onClick={() => {
            race(fetch("//xxx"), v => {
              ref.current.innerText = v
            })
          }}
        >
          show1
        </button>
        <button
          onClick={() => {
            race(fetch("//yyy"), v => {
              ref.current.innerText = v
            })
          }}
        >
          show2
        </button>
      </nav>
      <div ref={ref} />
    </div>
  )
}

div[ref]节点被两个 promise 写入,对应 id 为默认"default"。