用 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 */});
手头的一些事情:
这将是冗长而精确的,因为我真的想把我的问题说清楚
我已阅读 RXJS 文档
我看过这个
我正在用 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 */});