ES6 Promises - 在不使用延迟的情况下,我如何保证最终访问在 React componentDidMount 函数期间实例化的对象?

ES6 Promises - Without using a deferred, how can I guarantee eventual access to an object instantiated during a React componentDidMount function?

提前谢谢大家。

我是第一次使用 ES6 原生 promises(过去,我使用过 Q 或 Angular 的 $q 服务)。我有一个问题可以通过使用 deferred 轻松解决,并且惊讶地发现 ES6 promises 不使用它们。

我更惊讶地发现博客上有很多人将 deferred 的用法称为反模式。即使在阅读了一些谴责使用 deferred 的博客之后,我仍然不太明白为什么 - 他们的例子大部分都是我从一开始就不会使用 deferred 的地方,所以也许我遗漏了一些东西(并且不介意解释顺便说一下为什么它们不好)。但是为了保持在最佳实践的范围内,我试图弄清楚如何在不引入支持它们的库的情况下解决问题,我被困住了。

我正在使用 OpenLayers 库在我的 React/Redux 应用程序中创建地图。创建地图对象时,OpenLayers 需要一个 DOM 元素来放置地图。因此,在安装组件之前我无法实例化 OpenLayers 地图。没关系,componentDidMount 有一个生命周期钩子。

我 运行 遇到的一个问题是我需要将该地图对象公开给其他 classes 而那些 classes 的代码需要等待 [=44] =] 直到地图创建完成。

有了延迟,我可以相当简单地处理这个问题,如下所示:

const deferred = Q.defer();

const Foo = React.createClass({
  componentDidMount() {
    const map = new ol.Map(...);
    deferred.resolve(map);
  }
  ...
}

export getMap => deferred.promise

但是有了 ES6 承诺,我被卡住了。

我无法在 componentDidMount class 之外实例化承诺,因为它会立即触发。

如果我在 componentDidMount 函数的范围内实例化一个 promise(或使用 Promise.resolve,因为我的代码是同步的),则该 promise 超出了 getMap 函数的范围。

如果我在 componentDidMount 范围之外声明但不实例化 promise 对象,getMap 将 return 未定义,直到 componentDidMount 执行,首先破坏了拥有 promise 的意义。

作为最后的想法,我没有将地图置于 Redux 状态,因为 OpenLayers 地图是高度可变的并且做他们自己的事情,如果我将地图放在那里,它会破坏 Redux 对不变性的承诺......所以我放弃了 Redux 解决方案。在 Redux 状态上抛出某种布尔值,如 "mapAvailable" 感觉就像一个 hack。我可能可以完成这项工作,但它会引入许多次要问题。

那我错过了什么?我是处于极端情况下,延期确实是正确的答案,还是我只是没有看到明显的答案?

再次感谢您的宝贵时间。

I was further surprised to discover a large number of people on blogs referring to the usage of deferred as an anti-pattern.

您似乎指的是此处的 deferred antipattern,它是关于延迟的 特定 用法 - 它并没有说延迟是一种反模式。

尽管 :-) 您不需要任何延迟对象,resolve 函数绝对足够了。

I can't instantiate the promise outside of the componentDidMount class because it will fire immediately.

你为什么马上开火?只是不要那样做。您甚至可以将它包裹在 class:

周围
export const promise = new Promise(resolve => {
  const Foo = React.createClass({
    componentDidMount() {
      const map = new ol.Map(…);
      resolve(map);
    }
    …
  }
  … // do something with Foo here
});

但您更有可能想要这样做

let resolve;
export const promise = new Promise(r => {
  resolve = r;
});
export const Foo = React.createClass({
  componentDidMount() {
    const map = new ol.Map(…);
    resolve(map);
  }
  …
}

当然请注意,这是一个可怕的模式 - 您刚刚创建了一个 global、静态承诺,基本上是一个单例。当您的应用程序中可能包含的 any 组件被安装时,它将得到解决。不要那样做。我建议将 promise 放入组件的构造函数中,尽管我仍然不确定您到底需要它做什么。

您所处的情况是 deferred 可以正常工作,但它们已经过时了,这就是您发现博客将 deferred 用作反模式的原因。

您可以查看 this link,它将为您提供 deferred 已过时的更多详细信息。

我想到了与 mapAvailable 相同的解决方案,并同意这将是一个 hack。如果您找到针对这种情况的更好解决方案,请告诉我们。