V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yazoox
V2EX  ›  React

看到一段代码, setTimeout(resolve, 0), 不是很明白用意?

  •  
  •   yazoox · 2021-09-01 17:39:45 +08:00 · 3290 次点击
    这是一个创建于 1208 天前的主题,其中的信息可能已经有所发展或是发生改变。
    const whenStable = async () =>
      await act(async () => {
        await new Promise((resolve) => setTimeout(resolve, 0));
      });
    

    原帖地址: https://stackoverflow.com/questions/60137762/how-can-i-test-a-react-hooks-component-by-changing-usestate?rq=1 只有一个回复,回复里面的测试文件,里面用到了这个

    不是很理解这个的用意。如果说需要延时,那为什么 setTimeout 的参数是 0? 还是说,作者只是举个例子?应该设为比如 500,etc.?

    以及,这个貌似有 warning

    Warning: The callback passed to ReactTestUtils.act(...) function must not return anything.
    
    15 条回复    2021-09-03 13:08:04 +08:00
    Puteulanus
        1
    Puteulanus  
       2021-09-01 17:43:46 +08:00
    setTimeout 0 不是精确的没有延迟,看这意思是想等待到下个 event loop ?
    just1
        2
    just1  
       2021-09-01 17:43:57 +08:00
    类似于 nextTick
    misdake
        3
    misdake  
       2021-09-01 17:46:37 +08:00   ❤️ 1
    microtask 和 macrotask 的区别吧。promise 是 microtask 。setTimeout 是 macrotask,会在所有 promise 执行之后再执行。
    感觉原因应该是:界面变动都是通过 microtask 来实现的,setTimeout 的函数一旦运行就说明已全部执行完毕。
    RexG
        5
    RexG  
       2021-09-01 18:09:01 +08:00
    @just1 @misdake 说的都对,就是这个操作
    eason1874
        6
    eason1874  
       2021-09-01 18:14:28 +08:00   ❤️ 1
    用途是防阻塞。

    浏览器是按顺序处理事件的,setTimeout 回调事件排在页面普通 JavaScript 代码后面,所以比较占时间的 JavaScript 可以放到 setTimeout 里面,等页面渲染好再去执行,防止阻塞导致白屏什么的。

    setTimeout 不是真正的定时任务,意思是最快在这个时间执行,慢的话,说不准。如果前面事件有阻塞一辈子,那一辈子也不会执行。
    KouShuiYu
        7
    KouShuiYu  
       2021-09-01 18:15:52 +08:00
    估计是确保 DOM 已经更新
    violetlai
        8
    violetlai  
       2021-09-01 19:39:41 +08:00
    有些插件需要等 dom 更新 才搞这个
    2i2Re2PLMaDnghL
        9
    2i2Re2PLMaDnghL  
       2021-09-01 19:51:53 +08:00
    我觉得取个名字清楚点
    const nexttick = () => new Promise((resolve) => setTimeout(resolve, 0));

    //...
    await nexttick()
    //...

    至于你的 warning,则是来源于 act(async () => {}) 这部分。但理论上来说这段中确实不包含任何 return,是不是返回了一个 Promise<undefined> 的原因?
    wanguorui123
        10
    wanguorui123  
       2021-09-01 20:01:18 +08:00
    添加到事件队列末尾下个周期调用
    slime7
        11
    slime7  
       2021-09-01 20:39:38 +08:00
    我去抄 vuetify 的水波纹代码时也见过这个用法,用在添加水波纹动画的进入 class 上,我当时猜测是需要先设置一个初始样式,再用这个方式设置需要变形到的样式,这样才能产生 css 的 transition
    Taikyo
        12
    Taikyo  
       2021-09-01 22:40:43 +08:00
    加入宏任务,只是为了不让它被立刻执行,可以在下一个 event loop 去执行。
    xxz0315
        13
    xxz0315  
       2021-09-02 13:00:00 +08:00
    相当下一帧的意思
    yazoox
        14
    yazoox  
    OP
       2021-09-02 20:03:16 +08:00
    @2i2Re2PLMaDnghL
    有没有办法修改一下,消除这个警告?就按当前的用途
    2i2Re2PLMaDnghL
        15
    2i2Re2PLMaDnghL  
       2021-09-03 13:08:04 +08:00
    @yazoox 简单地
    act(async()=>{...})
    转化为
    act(()=>{(async()=>{...})()})

    但其实没有任何意义,是这个 warning 本身有问题。
    我猜想这个 warning 的设置似乎是为了避免有人「想当然地」用 act callback 传递测试失败信号。
    为了绕过一个过于宽泛的 warning 这么做不好,你应当修正 warning 的提供者。
    看上去这个 warning 不是 react 提供的,在 react 代码中全文搜索 "must not return anything" 类似文字均在处理要求 effect 只能返回一个函数。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2626 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:42 · PVG 18:42 · LAX 02:42 · JFK 05:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.