用 Observable 包装一个函数来创建一个热监听器

Wrap a function with an Observable to create a hot listener

手头的一些事情:

这将是冗长而精确的,因为我真的想把我的问题说清楚

我已阅读 RXJS 文档 我看过这个 post。 我还看过其他几个 post。 none,不幸的是,帮了我。

我正在用 Vue 2.6 编写

我创建了一个包装器来在我的 Vue 应用程序中轻松管理 RXJS 我在我的应用程序中实例化了一个 RXJS 实例作为单例对象

Vue.prototype.$rx = Rxjs;

我还将我的 RXJS 实例存储在我的 VUEX 中

store.commit('setProperty', {key: 'rx', value: Vue.prototype.$rx})

这样我就可以在我的 VUEX 商店中使用 RXJS

我的 RXJS 对象只是一个包装器

export const Rxjs = {
    create(namespace, subjectType = 'subject') {
        this[namespace] = new RxjsInstance(subjectType)
    }
}

它根据我的 VUEX 命名空间模块为我的应用程序中的每个命名空间实例化一个新的 RXJS class

所以对于“主页”屏幕,我有一个主页 VUEX 模块和一个 RXJS(如果需要 - 它们不会自动实例化)实例来保存主页的订阅 基于此 class:

export class RxjsInstance {
    constructor(subjectType) {
        this.subscriptions = new Subscription();
        switch (subjectType) {
            case 'subject':
                this.subject = new Subject();
                break;
            case 'asyncSubject':
                this.subject = new AsyncSubject();
                break;
            case 'behaviorSubject':
                this.subject = new BehaviorSubject(null);
                break;
            case 'replaySubject':
                this.subject = new ReplaySubject();
                break;
        }
    }

    next(data) {
        this.subject.next(data);
    }

    asObservable() {
        return this.subject.asObservable();
    }

    set add(subscription) {
        this.subscriptions.add(subscription);
    }

    subscribe(subscriber, callback) {
        if (!subscriber) {
            throw 'Failed to subscribe. Please provide a subscriber'
        }
        subscriber = this.asObservable().subscribe(data => {
            callback(data)
        });
        this.subscriptions.add(subscriber)
    }

    unsubscribe() {
        this.subscriptions.unsubscribe();
    }
}

简而言之 - 这个 class 字面上 returns 一个准系统的 RXJS 功能,其附加值是订阅自动保存在实例的本地数组中,以便更容易控制和防止内存泄漏 -没什么特别的 - 只是为我的团队简化。

就目前而言,我有一个 gloal RXJS 对象,它在我的应用程序中无处不在 - 我可以从每个组件访问它,并允许我将数据从 A 点传输到 B 点,而无需使用多个 'props' 以及父子组件之间等量的发射。 所有这一切都没有触及我的 VUEX 状态(与 Redux 不同,它不是不可变的) 所以当我改变我的状态时——它是干净和受控的数据。

现在解决我的问题。

我正在尝试找出一种方法来使用 RXJS 将现有函数与一个可观察对象包装起来,这样我就可以在函数被调用时订阅它。

假设我有一个 alertUser(msg) 函数,它只是将 'msg' arg 附加到我的 DOM.

中的

元素

我想 'subscribe' 这个函数 - 完全不改变它! 用一个可观察或分配一个给它。 我不确定这是否可行——因为我所看到的 RXJS 所做的只是创建一个执行该功能的可观察对象,然后将其替换为它。 但是因为我正在将 RXJS 集成到一个已经存在的应用程序中 - 我无法将所有内容重构为可观察的。

所以我的最终目标是

alertUser(msg){
    this.appendToPElement(msg)
}

this.localVariable = ObservThatFunction(){
\ this is where I want the magic to happen and listen to the alertMsg func and make this an observable i can subscribe to
}

this.sub = this.localvariable.subscribe(data=>{console.log(data)})

这可能吗?

编辑: observable 不必传递函数的数据 - 只需在调用函数时发出一个值(甚至是 bool 值)

例如,当 this.alertUser() 被调用时,我希望调用 observable - 我的订阅者现在可以更新通知服务,新消息已发送 - 无论该消息是什么

这里只是猜测,但也许 Proxy 会有所帮助。

    const handler = {
      apply: function(target, thisArg, argumentsList) {
        obs.next(true);
        return target(argumentsList);
      }
    };

   function observeFn(fn) {
     return new Proxy(fn, handler);
   }

然后你可以像这样包装你的原始函数:observeFn(alertUser)obs 应该通知对该函数的任何调用。

TL;DR: It is simply impossible.

简而言之,您想 监视 特定方法。在 JavaScript 中 可靠地 spy/stub 的唯一方法是使用 ES Proxy。但是代理就像一个方法的包装器。如果此函数是您要导出的对象的一部分,那么 Proxy 就可以工作。但事实并非如此。此外,您需要调用 proxied 函数,而不是直接调用原始函数。另一种方法是使用 JavaScript [装饰器][2],但它们还不是标准的,仅在 class/method 上下文中有用。

但是,作为一种解决方法,您可以在不更改语义并将其包装到可观察对象的情况下修改函数。这个想法是创建一个全局主题并从 alertUser():

调用它
window.messageQueue = new Subject();

alertUser(msg){
  this.appendToPElement(msg);

  // This is non-destructive.
  window.messageQueue.next(msg);
}

// Usage
window.messageQueue.subscribe(() => { /* next */});