RxJs fromEvent 工作原理分析

举报
Jerry Wang 发表于 2022/06/11 10:04:48 2022/06/11
【摘要】 fromEvent(this.test, 'click').subscribe((event) => console.log(event));this.test 的赋值逻辑:this.test = this.document.getElementById('test');每当该 id 为 test 的按钮被点击一次,则 fromEvent issue 一个新的值,内容为 MouseClick...
fromEvent(this.test, 'click').subscribe((event) => console.log(event));

this.test 的赋值逻辑:

this.test = this.document.getElementById('test');

每当该 id 为 test 的按钮被点击一次,则 fromEvent issue 一个新的值,内容为 MouseClick 事件:

本文介绍这个神奇的 fromEvent 的工作原理。

在 rxjs/_esm2015/index.js 下能看到所有 rxjs 支持的 operators:

fromEvent 构造函数支持最多 4 个输入参数,但我的例子里,之传入了两个。因此直接进入 Observable 对象的构造逻辑:

Observable 的构造函数,只有一个输入参数,该输入参数为一个函数。这个函数是一个匿名函数,只有函数体而无函数名称。

把该匿名函数维护在 Observable 的私有属性 _subscribe 里。

fromEvent 返回一个可观察对象,调用该对象的 subscribe 方法,给其注册观察者。

上图 observerOrNext 就是我们应用程序里,传入给 subscribe 方法的匿名函数,即使用 console.log 打印 id 为 test 的 button 被点击之后抛出的 MouseEvent 事件。

因为我们暂时没有给 fromEvent 返回的 Observable 对象指定 operator,因此第 20 行 operator 为 undefined:

调用函数 toSubscriber 创建一个新的 subscriber:

上图 nextOrObserver 就是我应用程序里指定的 console.log(event) 匿名函数,只是用 Subscriber 包了一层。

Subscriber.js 内部:Subscriber 的 destination 属性,指向了 SafeSubscriber 实例:

再回到 Observable 的 subscribe 方法。现在我们知道了,在其 toSubscriber 方法里,创建了一个 Subscriber 实例,其重要属性如上图1,2,3所示。因为没有为该 Observable 指定 operator,所以第 22 行的 IF 分支进不去,而是执行第 26 行的 else 分支。

进入 trySubscribe 方法:

_trySubscribe 是 _subscribe 方法的包裹,再加上错误处理:

文章开头提到的 Observable 私有属性 _subscribe, 指向 fromEvent.js 第14行匿名函数:

现在执行该匿名函数,函数体内 setupSubscription.

如何判断传进来的变量是 EventTarget 呢?

检查其是否具有 addEventListner 和 removeEventListener 即可。

这里把 fromEvent.js 里某个 handler 函数,作为按钮点击后的事件处理函数进行注册。

注意,这里给 click 点击事件注册的,并不是我们应用程序指定的 console.log(event), 而是 fromEvent.js 里一个内部函数,如下图所示:

当我点击 UI 的 test 按钮后,触发 click 事件,fromEvent.js 里定义的事件处理函数被调用:

还记得我们之前提到的 toSubscriber 函数调用么?将应用程序定义的 console.log(event), 包装成 SafeSubscriber,存储到 _next 属性里。

这里,最终触发 subscriber 的私有属性 _next 指向的应用程序处理逻辑:

使用了 JavaScript function 原生的 call 方法进行调用:

最终,进入了应用程序打印代码执行,谜底就此解开:

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。