0%

rxjs-create

Introduction

RxJS中有许多创建Observable的方法,如fromofinterval等,本文一一介绍。

from

from方法可以将一个数组、类数组对象、Promise、可迭代对象、Observable-like对象转换为Observable。

将数组转换为Observable

RxJS社区有一个约定,以$结尾的变量代表一个Observable对象。下面的例子将一个数组转换为Observable。

1
2
3
4
5
import { from } from 'rxjs';

const array = [1, 2, 3];
const array$ = from(array);
array$.subscribe(console.log); // 1, 2, 3

上面的代码可以简化为:

1
2
3
import { from } from 'rxjs';

from([1, 2, 3]).subscribe(console.log); // 1, 2, 3

将Promise转换为Observable

下面的例子将一个Promise对象转换为Observable。

1
2
3
4
5
6
const p = new Promise((resolve) => {
setTimeout(() => {
resolve([1, 2, 3]);
}, 1000);
});
from(p).subscribe(console.log);

将可迭代对象转换为Observable

其实数组就是可迭代对象,所以前面数组的例子已经包含该例子,下面的例子将一个可迭代对象转换为Observable。

1
2
3
4
5
6
7
function* generate123() {
yield 1;
yield 2;
yield 3;
}

from(generate123()).subscribe(console.log);

使用asapScheduler

使用asapScheduler可以让from方法在当前任务队列的末尾执行,下面的例子展示了如何使用asapScheduler。你知道以下代码输出什么吗?如果不加asapScheduler,输出会是什么?

1
2
3
console.log('from start...');
from([1, 2, 3], asapScheduler).subscribe(console.log);
console.log('from end...');

以上代码输出如下:

1
2
3
4
5
from start...
from end...
1
2
3

如果去掉asapScheduler,则from同步执行,输出如下:

1
2
3
4
5
from start...
1
2
3
from end...

from的以下书写方式已经被废弃,将在RxJS 8中移除.

1
from([1, 2, 3], asapScheduler).subscribe(console.log);

推荐使用下面的方式,详情看这里

1
scheduled([1, 2, 3], asapScheduler).subscribe(console.log);

将Dom事件转换为Observable

使用fromEvent方法可以将Dom事件转换为Observable。
以下代码监听documentclick事件,当点击document时,会在控制台输出clicked!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<script src="https://unpkg.com/rxjs@^7/dist/bundles/rxjs.umd.min.js"></script>
<title>rxjs demo</title>
</head>
<body>
<script>
const { fromEvent } = rxjs;
fromEvent(document, "click").subscribe(() => {
console.log("clicked!");
});
</script>
</body>
</html>

默认情况下,浏览器的事件模型是冒泡模型,也可以改为捕获模型,只需要传递{ capture: true }作为fromEvent的第三个参数即可。

1
2
3
fromEvent(document, "click", { capture: true }).subscribe(() => {
console.log("clicked!");
});

of

of把输入的值转换为Observable。与from不同的是,of不会做任何flatten操作,它会把输入的值当做一个整体。这一点体现在数组上,from会把数组的每个元素当做一个值,而of会把整个数组当做一个值。

1
2
3
import { of, from } from 'rxjs';
of([1, 2, 3]).subscribe(console.log); // [1, 2, 3]
from([1, 2, 3]).subscribe(console.log); // 1, 2, 3

of通常用在要一次性生成多个值的场景,比如下面的例子:

1
2
import { of } from 'rxjs';
of(1, 2, 3).subscribe(console.log); // 1, 2, 3

range

Emit a sequence of numbers in a range.

在一个范围内生成一个Observable。range方法有三个参数,分别是startcountschedulerstart表示起始值,count表示生成的个数,scheduler表示调度器。

1
2
3
import { range } from 'rxjs';

range(1, 3).subscribe(console.log); // 1, 2, 3

interval

interval方法会每隔一段时间发出一个递增的数字。interval方法有一个参数period,表示时间间隔,单位是毫秒。interval默认使用asyncScheduler

1
2
3
import { interval } from 'rxjs';

interval(1000).subscribe(console.log); // 0, 1, 2, 3, 4, ...

有三点需要注意:

  1. interval方法是异步的,默认使用asyncScheduler
  2. interval方法会从0开始发出数字。
  3. interval方法第不是立即执行的,而是在第一个时间间隔之后执行。

以下代码输出什么?

1
2
3
console.log('interval start...');
interval(1000).subscribe(console.log);
console.log('interval end...');

答:因为interval默认使用asyncScheduler,所以interval方法是异步的,所以interval start...interval end...会先输出,然后再输出0, 1, 2, 3, 4, ...

timer

可以将timer看成是高配版的interval,为啥这么说呢?因为interval只能设置时间间隔,却无法控制开始时间(interval的开始时间就是其时间间隔),而timer既能控制间隔时间,也能控制开始时间。

来看这样一个需求,每个1秒产生一个数字(从0开始),但是要求第一个数字立即产生,而不是等待1秒。interval无法满足这个需求,但是timer可以。

1
2
3
import { timer } from 'rxjs';

timer(0, 1000).subscribe(console.log); // 0, 1, 2, 3, 4, ...

timer方法的第一个参数就是开始时间,除了可以指定一个具体的毫秒数之外,还可以指定一个Date对象,表示在指定的时间开始。

1
timer(new Date(2024, 11, 28, 17, 0, 0), 1000).subscribe(console.log); // 0, 1, 2, 3, 4, ...