【问题标题】:Why to use BehaviorSubject in shared service and not use simple shared variables?为什么在共享服务中使用 BehaviorSubject 而不是使用简单的共享变量?
【发布时间】:2020-11-13 05:44:14
【问题描述】:

我对使用 BehiavorSubject 而不是在服务中使用共享变量感到有些困惑。如果我使用共享变量创建服务甚至覆盖它们,角度组件也会检测到这些变化,那我为什么要使用 BehiavorSubject 而不是共享变量呢? 例如,在我的项目中,如果用户登录,则会显示一个导航栏,因此我有 ngIf service.isLoggedIn 并且它工作正常。为什么我需要一个可观察的服务并订阅它的事件。如果有人从不同的组件更改此值,它也会在此处更改。我是 Angular 新手,如果我遗漏了什么,请告诉我。 谢谢 (我按照这个例子:https://loiane.com/2017/08/angular-hide-navbar-login-page/

【问题讨论】:

  • 您无法订阅共享变量的更改
  • 组件也检测到这些变化 - 如何?您需要从组件中主动轮询以了解变量是否已更改。使用BehaviorSubject,您只需订阅它并等待它更改。
  • 在我的项目中,我有一个导航栏,如果我登录则会显示该导航栏,因此我有 ngIf service.isLoggedIn 并且它工作正常。为什么我需要使用 observable 订阅。如果有人从不同的组件更改此值,它也会在此处更改。我是 Angular 新手,如果我遗漏了什么,请告诉我。
  • 观察未来的变化
  • 对不起,我不明白“观察未来的变化”

标签: angular observable angular-services behaviorsubject


【解决方案1】:

是的,您说得对,可以使用共享变量,进而可以检测到更改并相应地更新view

那我们为什么需要Subject or BehaviorSubject

简单的答案是

当它只是根据更新的共享变量直接更改视图时,如下所示,

 <div>Result : {{sharedService.result}}</div>

使用共享变量是有意义的。因此,在共享服务中,您只需将 result 更改为 10 并立即将 view 更新为 10 值。

但是

result10 时,在(任何)组件中,你想运行一些代码/逻辑吗?
如何确保当result 获得10 值时,会运行一些逻辑(在组件中?

如下所示,

some.component.ts

       if(sharedService.result === 10){  

             // This code can not run with shared variable approach

       }

问:我们可以在组件中写上类似的东西吗?
答:是的

Q:写完之后,会运行里面写的逻辑吗?
答:没有

问:为什么?
A:因为,共享变量是(使用服务)引用类型。这意味着无论何时更改值,应用程序中的所有引用都将更改(对于单例服务),但用 some.component.ts 编写的代码不会运行或触发。

问:为什么?
A:因为在javascript/angular中,要执行这种类型的场景/代码,你应该有callback的机制。

问:什么是回调?
A: 一个函数,可以作为参数传递给任何能够在主函数执行后自行执行的函数。

这是理解BehaviourSubject所需的基本知识。

现在,当您在服务中定义 behaviourSubject 时,如下所示,

Shared.Service.ts

    myBehaviorSubject = new BehaviourSubject(); // has ability to register a callback function     

您可以在以下任何组件中使用myBehaviorSubject

some.component.ts

    constructor(private sharedService:SharedService){

        // below subscribe line registers a callback function with myBehaviorSubject.

        this.sharedService.myBehavioirSubject.Subscribe((value)=>{     // This is callback function `(value)=>{...}` 

            if(value === 10){   // When value gets 10 value, below code will run automatically

                // This code will run when condition is met

            }
        })
    }

现在,behaviourSubject 有一些额外的机制来发出值。因此,如果我从this.myBehaviourSubject.next(10) 之类的任何地方发出10 值,由于behaviourSubject 的内部机制,将调用注册的回调函数。因为它是一个函数,所以当10值被发出时,一个回调函数会自行执行,它会运行函数内部编写的其他逻辑。

我希望,有了这种理解,您将能够理解为什么 shared variablesbehaviourSubject 不同

【讨论】:

  • 如果您认为最适合您的问题,您可以投票并接受答案。谢谢!
  • 我没有足够高的声誉来投票,我是新手...
  • 是的,我能理解。感谢您接受它!
【解决方案2】:

这是一个公平的问题。根据您的评论,将其保留为变量可能是最好和最简单的解决方案。不过,这里有一些我能想到的用例:

  • 每次值变化时执行逻辑。你也可以在变量的 set 函数中执行此操作,但是使用 RxJS 可以让你轻松访问强大的运算符,例如 debounce 和几个映射运算符。每次值更改时都需要进行 API 调用,但您想等到用户完成输入后再点击您的 API? RxJS 是一个很好的解决方案。

  • 您可以将它与其他 observables 结合使用。也许你有另一个事件流。将该变量设为 Observable,您可以轻松地将对该变量的更改插入到其他流中。

  • 更好的 Angular 性能。通过使用 BehaviorSubject (这是一种可观察的类型),您可以在 Angular 模板中放置对它的引用,并使用 async 管道自动订阅并在值更改时自动标记它以进行更改检测。所以它看起来像这样:service.isLoggedIn | async。如果您以这种方式完成整个组件,您最终可以将 ChangeDetectionStrategy 切换为 OnPush,后者的性能要高得多。或者更好的是,您可以切换到 ngrxPush 管道并将您的应用程序完全移出 Angular 区域,从而进一步提高性能。

请记住,即使您的更改“神奇地”更新了组件,但这种神奇是有代价的。 Angular 必须弄清楚发生了什么变化,并且不要认为它一开始就发现了这一点。它会持续监控您的应用程序——每次按钮点击、每次输入,有时甚至悬停事件都会触发更改检测。因此,您可以为 什么 更改以及 更改提供更多挂钩,您就可以更轻松地提高性能。

【讨论】:

  • 感谢您的回答。只是为了澄清性能,使用 service.isLoggedIn | async 将允许我将组件更改为 onPush,同时以我不会做的方式(使用简单变量)进行操作,这会带来更好的性能吗?我在网上看到的所有示例都使用了 BehaviorSubject,所以我只是想弄清楚为什么
  • 只有当 isLoggedIn 是一个 BehaviorSubject 时,您才能将它与 async 管道一起使用并打开 OnPush 策略的大门。
猜你喜欢
  • 2018-11-13
  • 1970-01-01
  • 2019-07-25
  • 2016-07-12
  • 2022-08-14
  • 2014-04-20
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多