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。如果您找到针对这种情况的更好解决方案,请告诉我们。
提前谢谢大家。
我是第一次使用 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。如果您找到针对这种情况的更好解决方案,请告诉我们。