【问题标题】:Why is the cancelledPromise pattern considered better than the isMounted() "antipattern" in React?为什么 cancelledPromise 模式被认为比 React 中的 isMounted() “反模式”更好?
【发布时间】:2019-06-17 00:48:15
【问题描述】:

请看这里:https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html 还有这里:How to cancel a fetch on componentWillUnmount 在这里:ismounted antipattern, track own property

在这两种情况下,他们都提到了 3 种方法:

  • 在您的 promise.resolve 中检查 this.IsMounted(),如果 `Compounted Has Unmounted
  • ,React 将为您正确返回
  • 在您的promise.resolve 中检查_isMounted,这是您在ComponentWillUnmount() 方法中手动跟踪的。
  • 使用可取消的承诺,这样你promise 永远不会解决。 这将解决你所有的问题,让它变得可爱。

除了,在第三种情况下,您的 promiseerror(),但在其他情况下也可能是 error()(例如 API 已关闭)。

所以实际上第三个选项归结为: - 在您的promise.error 中检查errorPayload.IsCancelled,这是您在cancellablePromise 对象中手动跟踪的,而该对象又由ComponentWillUnmount 中的手动调用触发。

所以这三个几乎相同:

当您处理promise 结果时,请检查与组件是否已经有unmounted 直接相关的此变量的值。

为什么他们断言第 3 个选项比其他 2 个更好,并且第 1 个选项是反模式。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    这里的关键元素是if (this.isMounted()) { setState(...) } 是一个反模式一般来说。它可能导致有用的警告被压制,因此它的出现应该受到怀疑,因为在大多数情况下,它代表了掩盖实际问题的机会。因此,即使在其行为与其他方法在功能上相同的情况下,其他方法也更可取。

    在 API 调用的情况下,您可能希望忽略 Promise 的结果是完全合理的,因为它不再相关。使用取消的 Promise 在语法和语义上将是否忽略结果的逻辑专门与 API 调用联系起来,从而防止未来开发人员意外在另一个上下文中使用代码并潜在地抑制有意义的警告的任何可能性。

    虽然差异可能是语义上的,但语义本身对可维护性具有价值。在这种情况下,可取消的 Promise 用于在结构上将关注点放在一起,将通常可能成为问题的行为附加到可以接受的特定情况。

    【讨论】:

    • 我明白了...我们是说 API 调用单独isMounted() 的合理使用。但是如果我们使用可取消的承诺,那么我们就可以说“现在,isMounted() 永远不正确。”。对于其他情况,它更易于维护和保护。
    • 另一个类比:GOTO 被(规范地)认为是有害的。但是ifwhilebreakcontinueswitch 基本上都在做同样的事情,但声明了可以合理使用该概念的可接受情况。
    【解决方案2】:

    isMounted 组件方法已弃用。它不能再在 React 16 中使用。

    没有内置的_isMounted 状态,它应该由用户在组件生命周期钩子中定义。在某种程度上,这是一个偏好问题。它的问题是它需要承诺链耦合到组件实例才能访问this._isMounted

    对于可取消的承诺,这不是问题。更重要的是,这种模式允许实际取消异步过程,例如Axios 实际上在取消期间取消了 XHR 请求。尽管如此,为了完成这项工作,这需要整个承诺链都具有取消意识。这可能很乏味,因为本机承诺不支持取消,包括 async..await

    Observables 提供了更强大的方法来控制执行。有一个点(订阅)可以通过调用取消订阅函数取消整个链:

    const unsubscribe = fetchData()
    .mergeMap(asynchronousProcessing)
    .mergeMap(yetAnotherAsynchronousProcessing)
    .subscribe(data => this.setState(data));
    

    【讨论】:

      【解决方案3】:

      让我们想象一下将导致未来setState 调用的操作进行大量计算,或者进行大量网络请求。所有这些资源都将被使用,然后在未来某个时候,当 Promise 解决时,它意识到不需要所有工作,因为用户已经离开了页面的那部分,并且所有工作都将被丢弃。这对性能和网络/内存使用不利,特别是如果您有很多出现和消失的元素。如果您选择选项 3,则只有少量资源会被浪费,直到到达下一个停止点并释放资源。我假设他们删除了 1) 以强制代码编写者使用 3),并建议 2) 用于不可能/难以迁移的情况。

      【讨论】:

      • 不正确 - 在承诺解决之前,取消承诺不会做任何事情 - 这些不是取消令牌被传递给执行工作的服务器 - 它们只是关于如何承诺解决了。
      • @brondahl 依赖于 how 您取消基础操作。
      • 有趣...我以前没有遇到过,但是...基于该页面,您仍然具有完全相同的承诺逻辑,刚才检查是 if (err.name === 'AbortError') 而不是 @987654324 @。 (1/2)
      • 关于停止工作,如果它实际上是在告诉服务器停止工作(即杀死服务器线程),如果它是在浏览器级别实现的,我会感到非常惊讶。 (因为这需要每个浏览器都知道如何将该消息发送到每个服务器和服务器端框架)我怀疑它只是告诉浏览器不要听服务器的响应。因此,您所做的一切就是将“但然后什么都不做”推到更便宜的一步。 (2/2)
      猜你喜欢
      • 2010-11-22
      • 2012-09-27
      • 2012-01-02
      • 2015-05-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-02
      • 2014-08-30
      相关资源
      最近更新 更多