hooks icon indicating copy to clipboard operation
hooks copied to clipboard

useRequest runAsync 和 run 可能存在竞态

Open LaamGinghong opened this issue 1 year ago • 13 comments

https://stackblitz.com/edit/react-ts-pskjg5?file=App.tsx

通过 useUpdateEffect 状态变更执行 run,同时手动执行 runAsync,此时 runAsync 可能永远无法 resolve

LaamGinghong avatar Mar 09 '23 03:03 LaamGinghong

我在你的例子上做了点修改:https://stackblitz.com/edit/react-ts-pbtzon?file=App.tsx 无法复现你说的情况,我猜你的 log 打印的有歧义,导致你理解错了? @LaamGinghong

liuyib avatar Mar 11 '23 11:03 liuyib

@liuyib 还是使用我的原 demo,按照以下步骤必现:

  1. 点击左侧按钮进行 setNum(可以多点几次)
  2. 点击右侧按钮,此时会同时执行 setNum 和 runAsync
  3. 因为使用 useUpdateEffect 去处理 num 的副作用,num 变化时执行 run

我理解出现这个问题的原因应该是内部对请求进行合并,后面的 run 将第一次的 runAsync 取消了以确保请求回来的 data 一定是最后一次 run 执行回来的。

我认可这种行为,但我认为被合并的异步行为是否应该要 reject 掉或者 resolve 掉,目前 runAsync 是一直在 pending 的状态

LaamGinghong avatar Mar 14 '23 09:03 LaamGinghong

你好 我按照你的步骤,再次尝试了你的 demo,还是 get 不到你说的点。

请问:你的 demo 怎么证明 请求合并后 runAsync 是一直在 pending 的状态?或者说请求合并后 resolve 没有被执行?没有 log 或者其他东西直接证明,只是能看到 console.log(num); 少输出了而已。

你用我改过的 demo 试试,我在 resolve() 上一行加了 log,不管怎么点 以及 请求合没合并,都得看到预期的 log 的

liuyib avatar Mar 14 '23 15:03 liuyib

@liuyib image

可以看到首先我点击了两次左侧的按钮,然后再点击右侧的按钮,圈起来的 console.log('after request') 并没有被执行

LaamGinghong avatar Mar 15 '23 05:03 LaamGinghong

image 然后我们如果直接打印 runAsync,可以看到控制台的 Promise 显示的状态就是 pending

LaamGinghong avatar Mar 15 '23 05:03 LaamGinghong

https://stackblitz.com/edit/react-ts-irlzn6?file=App.tsx @liuyib 这个例子就能够看到了,onSuccess 里面根本没有打印 async

LaamGinghong avatar Mar 15 '23 05:03 LaamGinghong

@LaamGinghong 按照你的步骤复现了,确实存在这个现象,很感谢你的反馈。不过暂时还不确定是不是 bug,先执行 runAsync 再执行 run,就会使得 runAsync 一直 pending。让大佬看看 @crazylxr 见哥 有空看看这个

liuyib avatar Mar 15 '23 12:03 liuyib

https://github.com/alibaba/hooks/blob/d5fd82c5886d781ef12d8ff176ed9d03038e089b/packages/hooks/src/useRequest/src/Fetch.ts#L83

假设servicePromise是一个异步3秒的函数,3秒内暴击触发3次 runAsync ,因为是在异步后访问 this.count,3次拿到的值都会是3,这就导致会有一次的 runAsync 走进 https://github.com/alibaba/hooks/blob/d5fd82c5886d781ef12d8ff176ed9d03038e089b/packages/hooks/src/useRequest/src/Fetch.ts#L85

而这个Promise没有 resolve,所以永远 pending。是不是可以考虑在这里直接 Promise.resolve(res)

eon-lee96 avatar Mar 30 '23 13:03 eon-lee96

runAsync 没有 resolve我也遇到了 但是我无法100%复现 我就简简单单调用 一开始好好的 莫名就不行了

rain0002009 avatar May 26 '23 11:05 rain0002009

      const promises = [runAsync('abc'), runAsync('def')];
      
      console.log(promises);
      await Promise.all(promises);

这个不能这样用吗?其中一个一直都是pending,Promise.all就没办法resolve

lahvey avatar Jul 10 '23 01:07 lahvey

这个问题很蛋疼 找了好久问题才发 智慧触发最后一个的数据

xmsz-stu avatar Aug 07 '23 06:08 xmsz-stu

连续执行多次runAsync, 只会resolve一次,其他的全部pending

  if (currentCount !== this.count) {
    // prevent run.then when request is canceled
    return new Promise(() => {});
  }
image

coding-ice avatar Jan 08 '24 10:01 coding-ice

      const promises = [runAsync('abc'), runAsync('def')];
      
      console.log(promises);
      await Promise.all(promises);

这个不能这样用吗?其中一个一直都是pending,Promise.all就没办法resolve

使用 fetchKey 让useRequest并行,就可以用Promise.all 了

elliotmessi avatar Jan 12 '24 08:01 elliotmessi

runAsync 没有 resolve我也遇到了 但是我无法100%复现 我就简简单单调用 一开始好好的 莫名就不行了

+1,我也遇到了,在上一个没结束时,发出另一个请求,有一个请求一直是pending,求问有解决方法吗

soulcm avatar Mar 08 '24 01:03 soulcm

image 目前 useRequest 是只能串行请求的,在上一个请求还没完成之前,再发下一个,上一个会被忽略掉,会一直 Pending,从之前的设计上就是这样的。 我们在下一个版本把这种 case 考虑进去

关联的 issue:https://github.com/alibaba/hooks/issues/2078

这个 issue 就先 close 了,用上面的 issue 跟进这个问题

crazylxr avatar Mar 11 '24 01:03 crazylxr