简体   繁体   English

用 Observable 包裹 function 以创建热监听器

[英]Wrap a function with an Observable to create a hot listener

Few things before hand:手头有几件事:

This is going to be long and precise cause I really want to make my problem clear这将是漫长而准确的,因为我真的很想弄清楚我的问题

I've read the RXJS docs I've seen this Wrap an API function in an RxJs Observable post.我已经阅读了 RXJS 文档我已经看到了这个Wrap an API function in an Z04ACE71AEEBCA5D8D9DC642 post。 I've seen several other posts.我看过其他几个帖子。 none, unfortunately, helped me out.不幸的是,没有人帮助我。

I'm writing in Vue 2.6我正在用 Vue 2.6 编写

I've created a wrapper to easily manage RXJS in my Vue application I've instantiated an RXJS instance as a singletone object in my application我创建了一个包装器,以便在我的 Vue 应用程序中轻松管理 RXJS 我在我的应用程序中将 RXJS 实例实例化为单音 object

Vue.prototype.$rx = Rxjs;

I've also stored this instance of my RXJS in my VUEX我还在我的 VUEX 中存储了我的 RXJS 的这个实例

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

So that I can utilise RXJS in my VUEX store这样我就可以在我的 VUEX 商店中使用 RXJS

my RXJS object is just a wrapper我的 RXJS object 只是一个包装

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

which instantiates a new RXJS class for each namespace in my application based on my VUEX namespaced modules它根据我的 VUEX 命名空间模块为我的应用程序中的每个命名空间实例化一个新的 RXJS class

So for a "Homepage" screen I've got both a Homepage VUEX module an now an RXJS (if is needed - they do not instantiate automatically) instance to hold homepage's subscriptions based on this 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();
    }
}

In short - this class literally returns a barebone RXJS functionality with the added value of having the subscriptions automatically saved in a local array of the instance for easier control and prevention of memory leaks - nothing fancy - just simplification for my team.简而言之 - 这个 class 从字面上返回准系统 RXJS 功能,其附加值是让订阅自动保存在实例的本地数组中,以便更轻松地控制和预防 memory 泄漏 - 没有什么花哨的 - 只是为了我的团队泄漏。

So as it stands I've got a gloal RXJS object that sits everywhere in my application - that I can access from every component and allows me to transmit data from point A to point B without having to use several 'props' and an equal amount of emits between parent and child component.因此,就目前而言,我有一个全局 RXJS object,它位于我的应用程序的任何地方——我可以从每个组件访问它,并允许我将数据从 A 点传输到 B 点,而无需使用多个“道具”和等量of 在父组件和子组件之间发射。 all that without touching my VUEX state (which unlike Redux is not an immutable) So that when I do mutate my state - Its clean and controlled data.所有这一切都没有触及我的 VUEX state(与 Redux 不同,它不是一成不变的)所以当我改变我的 state 时 - 它的干净和受控的数据。

NOW for my problem.现在解决我的问题。

I'm trying to figure out a way to use RXJS to wrap an existing function with an observable so that I can subscribe to it whenever the function is called.我正在尝试找出一种方法来使用 RXJS 将现有的 function 包装为可观察的,以便我可以在调用 ZC1C425268E68385D1AB5074C17A94F14 时订阅它。

Lets say I've got a alertUser(msg) function which just appends the 'msg' arg to a假设我有一个 alertUser(msg) function ,它只是将“msg”参数附加到

element in my DOM.我的 DOM 中的元素。

I'd like to 'subscribe' to this function - without changing it at all!我想“订阅”这个 function -完全不改变它! by wrapping it with an observable or assigning one to it.通过用 observable 包装它或为其分配一个。 I'm not sure that's doable - because all I've seen RXJS doing is creating an observable that performs the function and then subbing to it.我不确定这是否可行——因为我所看到的 RXJS 所做的只是创建一个执行 function 的可观察对象,然后对其进行替换。 but because I'm integrating RXJS into an already existing application - I can't refactor everything to an observable.但是因为我将 RXJS 集成到一个已经存在的应用程序中 - 我无法将所有内容重构为可观察的。

So my end goal is所以我的最终目标是

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)})

is this even possible?这甚至可能吗?

EDIT: the observable doesn't have to pass the function's data - just emit a value (even a bool value) when the function is called编辑: observable 不必传递函数的数据 - 只需在调用 function 时发出一个值(甚至是布尔值)

so for example when this.alertUser() is called i want the observable to called - and my subscriber can now update the notification service that a new msg has been sent - regardless of what that message is因此,例如,当 this.alertUser() 被调用时,我希望调用 observable - 我的订阅者现在可以更新通知服务已发送新的 msg - 无论该消息是什么

TL;DR: It is simply impossible. TL;DR:这简直是不可能的。

In short, you want to spy over a particular method.简而言之,你想监视一个特定的方法。 The only way to reliably spy/stub in JavaScript is using ES Proxy .在 JavaScript 中可靠地监视/存根的唯一方法是使用ES Proxy But proxy is like a wrapper around a method.但是代理就像一个方法的包装器。 If this function is part of object which you are exporting, then Proxy would have worked.如果此 function 是您要导出的 object 的一部分,则代理将起作用。 But that is not the case.但事实并非如此。 Also, you need to call the proxied function and not the original one directly.此外,您需要直接调用代理function 而不是原来的。 Another way is to use JavaScript [Decorators][2] but they are not yet standard and useful in the class/method context only.另一种方法是使用 JavaScript [装饰器][2],但它们还不是标准的,仅在类/方法上下文中有用。

But, as a workaround, you can modify the function without changing the semantics and wrapping it into observable.但是,作为一种解决方法,您可以修改 function 而不更改语义并将其包装成 observable。 The idea is to create a global Subject and call it from the alertUser() :这个想法是创建一个全局主题并从alertUser()调用它:

window.messageQueue = new Subject();

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

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

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

Just guessing here, but maybe a Proxy could be helpful.只是在这里猜测,但也许代理可能会有所帮助。

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

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

Then you could just wrap your original function like this: observeFn(alertUser) and obs should notify any call to that function.然后你可以像这样包装你原来的 function: observeFn(alertUser)obs应该通知对 function 的任何调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM