我在Reactive中搜索了延迟使用,但我仍然不明白为何以及何时使用延迟方法。
据我所知,所有Observable方法在订阅之前都不会被触发,那么,为什么我们需要用defer方法包装observable方法?
请给我建议,如果给我一些例子,我将非常感激。
[更新]
现在我明白了。
在反应式文档中,我看到了这个例子,
var source = Rx.Observable.defer(function () {
return Rx.Observable.return(42);
});
var subscription = source.subscribe(
function (x) { console.log('Next: ' + x); },
function (err) { console.log('Error: ' + err); },
function () { console.log('Completed'); } );
我很想知道,
为什么它用延迟包装Observable方法?它将如何采取不同的行动?
答案 0 :(得分:25)
很简单,因为Observables
可以封装许多不同类型的来源,而这些来源不一定必须服从该界面。像Promises
这样的人总是试图热切地竞争。
考虑:
var promise = $.get('https://www.google.com');
在这种情况下的承诺已经在任何处理程序连接之前执行。如果我们希望这更像Observable
,那么我们需要某种方式推迟创建承诺,直到订阅为止。
因此,我们使用defer
创建一个仅在订阅结果Observable
时才会执行的块。
Observable.defer(() => $.get('https://www.google.com'));
在Promise
订阅之前,上述内容不会创建Observable
,因此会更符合标准Observable
界面。
答案 1 :(得分:3)
以(From this article)为例:
const source = Observable.defer(() => Observable.of(
Math.floor(Math.random() * 100)
));
为什么不将source
的“可观察”设置为of(Math.floor(Math.random() * 100)
?
因为如果这样做,表达式Math.floor(Math.random() * 100)
将立即运行,并在我们订阅source
之前作为值在source
中可用。
我们要延迟对表达式的求值,因此我们将of
包装在defer
中。现在,Math.floor(Math.random() * 100)
会在订阅source
时(而不是更早的时间)进行求值。
我们将of(...)
包装在defer
工厂函数中,使得of(...)
的构造在观察到source
的情况下发生。
答案 2 :(得分:2)
一个例子,假设您要向服务器发送请求。您有2个选择。
通过XmlHttpRequest
如果您不subscribe
使用现有的 Observable Observable.create(fn)
,将不会有任何网络请求。当您subscribe
时,它仅发送请求。这是正常现象,应该通过Observables进行。它的主要优点。
通过Promise (从Promise获取,rx)
当您使用Promises时,它将无法正常工作。无论您是否订阅,它都会立即发送网络请求。要解决此问题,您需要将Promise包装在defer(fn)
中。
答案 3 :(得分:1)
实际上,您可以将defer
完全替换为常规功能。但是您必须在订阅之前调用该函数。
function createObservable() {
return from(fetch('https://...'));
}
createObservable().subscribe(...);
对于defer
,您只需要将createObservable
函数传递给defer
。
答案 4 :(得分:0)
如果我们考虑使用日期,将会更容易理解。
const s1 = of(new Date()); //will capture current date time
const s2 = defer(() => of(new Date())); //will capture date time at the moment of subscription
对于两个可观察对象(s1和s2),我们都需要订阅。但是,当订阅s1时,它将给出设置常量时的日期时间。 S2将提供订阅时的日期时间。
以上代码取自https://www.learnrxjs.io/operators/creation/defer.html
答案 5 :(得分:0)
假设您要创建一个可观察的对象,在订阅时,该对象执行一个ajax请求。
如果您尝试使用以下代码,则会立即执行 ajax请求, 5秒钟后,将打印响应对象,这不是您想要的。
const obs = from(fetch('http://jsonplaceholder.typicode.com/todos/1'));
setTimeout(()=>obs.subscribe((resp)=>console.log(resp)), 5000)
一种解决方案是手动创建一个Observable
,如下所示。
在这种情况下,ajax响应将在5秒后(调用subscribe()
时)执行:
let obs = new Observable(observer => {
from(fetch('http://jsonplaceholder.typicode.com/todos/1')).subscribe(observer)
});
setTimeout(()=>obs.subscribe((resp)=>console.log(resp)), 5000)
defer
以更直接的方式实现了上述目标,并且无需使用from()
将诺言转换为可观察的结果:
const obs = defer(()=>fetch('http://jsonplaceholder.typicode.com/todos/1'))
setTimeout(()=>obs.subscribe((resp)=>console.log(resp)), 5000)