Rxjs,理解推迟

时间:2016-08-04 10:16:04

标签: rxjs

我在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方法?它将如何采取不同的行动?

6 个答案:

答案 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)