我是如何逆向工程 RxJS 并学习响应式编程的?(第二部分)
朋友们好,很高兴你们能看到本系列的第二部分。如果你还没看过第一部分,请点击下方链接查看。
在第一部分中,我们讨论了observables一些核心概念Reactive Programming。在第二部分中,我们将继续深入探索响应式编程,并继续逆向工程之旅RxJs。我们将讨论如何逆向工程诸如Rx.map`a`和 `b` 之类的运算符filter。我们还将了解如何在 JavaScript 中observable替换Promises`a`。
如果您使用过AngularWeb 应用或其他类似应用,您可能已经注意到,我们会在组件之间传递数据。例如,当发出 API 请求时,我们会收到一些数据,并根据这些数据更新组件的状态。有时,我们还会过滤一部分数据并将其传递给其他组件。
我这么说的目的是什么呢?你看,当我们在应用程序中发起 API 调用或发生用户交互时,就会生成一个数据流。我们可以使用一个 Observable 来监听这个数据流observable,此外,我们还可以创建另一个observablesObservable 来监听这个数据流observable。在大型应用程序中,我们经常会看到这种 Observable 的链式调用。从另一个 Observable 返回另一个 Observable 是该库的核心功能之一RxJs。
下面这张图展示了应用程序中的数据流。
好的,在我们的响应式库中,我们也希望能够将多个可观察对象链接起来。首先,我们需要模拟一个api调用。那么,让我们开始吧。
function fakeApi(param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(100)
}, 1000);
})
// or reject
}
如您所见,此函数返回的是一个 Promise 对象。现在,让我们将这个基于 Promise 的函数替换为使用 Observable 对象。
const o = new Observable();
function fakeApi(param) {
setTimeout(() => {
o.emit(100);
}, 1000);
}
我们没有使用 Promise 来解析结果,而是通过 Observable 来发出结果。请注意,我们的代码运行正常。我相信你observables现在已经开始体会到它的强大之处了。是不是很有意思? 😊😊
现在我们想o用另一个可观测对象进行观察,就像上面的图一样。那么我们该怎么做呢?我们已经有一个pipe函数了。如果你还记得上一篇文章中的例子,我们有以下代码:
const pipe = (...funcs) => x => funcs.reduce((effects, f) => f(effects), x);
现在让我们把这个管道函数添加到我们的Observable类中,并返回一个新的Observable
class Observable {
constructor() {
this.fnArray = [];
}
subscribe(fn) {
this.fnArray.push(fn);
}
emit(v) {
this.fnArray.map(fun => fun(v));
}
+ pipe(observable) {
+ const fn = x => observable.emit(x);
+ this.subscribe(fn);
+ }
}
所以在管道方法中,我们接收了另一个可观察对象,使用该传入的可观察对象通过柯里化函数发出一个值,然后我们订阅该柯里化函数。
那么,我们为什么要这样做呢?因为我们需要能够传递一个可观察对象并返回另一个可观察对象。让我们来看一下下面的代码。
const o = new Observable();
const o2 = new Observable();
function fakeApi(param) {
setTimeout(() => {
o.emit(1);
o.emit(2);
o.emit(3);
}, 1000);
}
fakeApi();
o.pipe(o2);
o2.subscribe(
pipe(
double,
double,
printFunction
)
);
o现在正在向另一个可观察对象传输数据o2。
outputs
I will print the 4
I will print the 8
I will print the 12
很酷吧?好,我们再进一步。现在我们将尝试map为 observable 实现我们自己的操作符。如果你去 Rx.js 的官方文档,你会找到一个合适的定义map。
https://rxjs-dev.firebaseapp.com/api/operators/map
简而言之,
map这是一个接受一个函数作为参数,应用该函数并返回一个新的可观察对象的函数。
如果你看一下下面的图片,就更容易理解了。
class Map {
constructor(func) {
this.observable = new Observable();
this.func = func;
}
subscribe(cb) {
this.observable.subscribe(cb);
}
emit(x) {
const val = this.func(x)
return this.observable.emit(val);
}
}
我们创建了一个名为 `Observable` 的类Map。在构造函数中,我们初始化一个新的 `Observable` Observable,并将传入的 `Observable` 存储在 `Observable` 函数func中。在 ` Observable` 函数中,subscribe我们订阅了该特定的 ` Observable` observable。最后,在 `Observable`emit函数中,我们应用this.fun带有 `param` 的 ` Observable` x,并返回emit我们初始化的 `Observable` 的 `Observable`。
由于map`is` 是 JavaScript 中的一个关键字,我们应该将映射封装在一个对象中。那么,让我们这样做吧。
const Rx = {};
Rx.map = f => new Map(f);
这里我们创建了一个空对象Rx,并将其键设置map为一个柯里化函数,该new Map()函数使用传入的函数初始化一个对象。现在我们可以像下面这样使用这个映射:
let c = o.pipe(Rx.map(v => v * -3));
c.subscribe(
pipe(
double,
printFunction
)
);
输出
I will print the -6
I will print the -12
I will print the -18
好了,我们现在有了自己的 map 方法。类似地,我们也可以对filter运算符进行逆向工程。
让我们去RxJs文档看看它是如何工作的。http
://reactivex.io/documentation/operators/filter.html
这张图让我们更全面地了解了它的功能。它类似于 map 函数,接收一个函数作为参数。唯一的区别在于它是一个比较函数。那么,让我们来构建它吧。
class Map {
constructor(func) {
this.observable = new Observable();
this.func = func;
}
subscribe(cb) {
this.observable.subscribe(cb);
}
emit(x) {
const val = this.func(x);
return this.observable.emit(val);
}
}
//...
Rx.map = f => new Map(f);
当我们像以前那样运行它时,我们会得到
let c = o.pipe(Rx.filter(v => v > 0));
c.subscribe(
pipe(
double,
printFunction
)
);
// output
I will print the 4
I will print the 6
希望你现在能看出其中的规律。RxJs运算符本质上就是执行特定任务的函数,我们可以将它们拆解开来。
希望这篇文章对您有所帮助,如果您想阅读更多文章,请留言、点赞、分享并关注我
。🚀🚀🚀🚀🚀🚀



