扩大运营商执行时间,超出预期

时间:2019-05-28 14:17:51

标签: angular typescript rxjs reactive-programming

我正在尝试使用扩展运算符构建一些对结果集进行分页的代码,并这样做直到获取一定数量的资源为止。这是我到目前为止的内容(删除了实际的异步调用逻辑):

import { Observable } from 'rxjs';

const items = [
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
    [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
];

const call = () => {
    console.log('#call');

    const batch = items.shift();

    if (batch) {
        return Observable.of(batch).delay(100);
    }

    return Observable.empty();
}

const o$ = call().expand((values) => {
    console.log('expansion');
    return call();
}).flatMap((val: any) => val);

const log = (prefix: string) => (...args: any[]) => console.log(prefix, ...args);

o$.take(9).subscribe(log('next'), log('error'), log('complete'));

输出与我想要的输出不同:

#call
takeWhile.ts:26 next 1
takeWhile.ts:26 next 2
takeWhile.ts:26 next 3
takeWhile.ts:26 next 4
takeWhile.ts:26 next 5
takeWhile.ts:26 next 6
takeWhile.ts:26 next 7
takeWhile.ts:26 next 8
takeWhile.ts:26 next 9
takeWhile.ts:26 complete
takeWhile.ts:22 expansion
takeWhile.ts:10 #call

我得到了9项,这是我使用take所要求的,然后流完成了,但是又发生了一次扩展,并且再次调用了模拟异步API。

有什么方法可以使我的代码变得更少贪婪并且不启动另一个递归迭代?

1 个答案:

答案 0 :(得分:0)

您期望的行为是预期的:expandtake之前被调用,所以

  • 我们得到第一个值
  • expand被执行并进行呼叫
  • 然后立即取消订阅整个可观察项

因此,您需要使递归调用异步进行,以使take取消预订之前。最简单的解决方法似乎是将return call();替换为return timer(4).map(call);(或者甚至是return defer(call);,这在魔术上很有效:/)。

See this example in action

因此,通常,您需要创建“暂停” /“间隙”,以使限制器启动并取消订阅。

希望这会有所帮助