Angular 8:单例服务每次需要在新文件上创建新实例时都会创建新实例

Angular 8:单例服务每次需要在新文件上创建新实例时都会创建新实例,angular,rxjs,observable,angular-services,behaviorsubject,Angular,Rxjs,Observable,Angular Services,Behaviorsubject,我有一个完全工作的平台,它在服务中使用Rxjs行为主体(可观察对象),以保持整个应用程序的状态。在我需要包含WebSocket来更新同一帐户中多个用户的信息之前,它一直工作得很好。 当更新的信息传递给用户时,我调用behavior subject来检查活动供应商(用户当前看到的供应商)是否应该更新,但可观察对象始终返回“null”,因为它是该可观察对象的新实例(与用户屏幕上显示的不一样) 为了测试它,我在两个不同的文件中记录了相同的观测值: //Supplier.service.ts impor

我有一个完全工作的平台,它在服务中使用Rxjs行为主体(可观察对象),以保持整个应用程序的状态。在我需要包含WebSocket来更新同一帐户中多个用户的信息之前,它一直工作得很好。 当更新的信息传递给用户时,我调用behavior subject来检查活动供应商(用户当前看到的供应商)是否应该更新,但可观察对象始终返回“null”,因为它是该可观察对象的新实例(与用户屏幕上显示的不一样)

为了测试它,我在两个不同的文件中记录了相同的观测值:

//Supplier.service.ts

import { Injectable } from "@angular/core";
import { BehaviorSubject } from 'rxjs';
import { Supplier } from '../../models/supplier.model';
import { UserService } from './User.service';

@Injectable({providedIn: 'root'})
export class SupplierService {
  activeSupplier = new BehaviorSubject<Supplier>(null);

  constructor (
    private http: HttpClient,
    private userService: UserService,
  ) {}

{...}

getOneSupplier(supplierId: string) {
  this.http.get<Supplier>(`${BASEURL}supplier/${supplierId}`)
    .subscribe(supplier => {
        this.activeSupplier.next(supplier);
        this.activeSupplier.pipe(take(1)).subscribe(activeSupplier => {
        console.log('updater:', activeSupplier); // <----------------- here
    });
  });
}

updateSupplierList(changedSupplier) {
    this.activeSupplier.pipe(take(1)).subscribe(activeSupplier => {
      console.log('Socket changing active supplier:', activeSupplier);
        if (activeSupplier._id === changedSupplier._id) {
          this.getOneSupplier(activeSupplier._id);
      }
    });
  }

{...}

}
import { Injectable } from '@angular/core';
import io from './SocketCopier.js';
import { UserService } from './User.service.js';
import { SupplierService } from './Supplier.service.js';

@Injectable({
providedIn: 'root',
})
export class SocketService {
socket;
subs = {};

constructor(
private userService: UserService,
private supplierService: SupplierService
) {
this.supplierService.activeSupplier.subscribe(activeSupplier => {
  console.log('socket:', activeSupplier); // <----------------- and here
});
}

loadSocket(user) {
io.then((result) => {
  if (this.socket) {
    this.socket.close();
  }

  this.socket = result('http://localhost:3000');
  this.socket.on('connect', () => {
    this.socket.emit('login', { account: user.account._id })
  });

  this.socket.on('logged', (msg) => {
    console.log(msg.text);
  });

  this.socket.on('supplierChange', (msg) => {
    this.supplierService.updateSupplierList(msg.data);
  });
});
}

}
import { Component, OnInit, OnDestroy } from '@angular/core';
import { SupplierService } from 'src/app/shared/services/Supplier.service';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Supplier } from 'src/app/models/supplier.model';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-supplier-info',
  templateUrl: './supplier-info.component.html',
  styleUrls: ['./supplier-info.component.css'],
})
export class SupplierInfoComponent implements OnInit, OnDestroy {
  supplier: Supplier;
  subs = {};
  activeRoute: string = 'projetos';

  constructor(
    private supplierService: SupplierService, 
    private route: ActivatedRoute,
    private router: Router,
    ) { }

  ngOnInit() {
      this.supplierService.getOneSupplier(this.route.snapshot.params.supplierId);
  }

  {...}

}
代码首先调用Socket.service.ts,它调用Supplier.service.ts,它创建行为主体“activeSupplier”,初始值为“null”

然后,Socket.service.ts在其构造函数中订阅可观察的“activeSupplier”,并按预期返回“null”

然后生成supplier-info.component.ts,并在ngOnInit中调用“this.supplierService.getOneSupplier()”以获取供应商信息。这将更新记录供应商的“activeSupplier”行为子对象

这是我从这些日志中得到的结果:

socket: null
updater: {socialMediaUrls: {…}, photoUrl: "", emails: Array(0), skills: Array(0), tags: Array(4), …}
Socket的observable不再更新,因为它是“supplierService”的一个新实例,并且它与supplier-info.component.ts不共享同一个“activeSupplier”。应该更新,对吗?因为它与相同的可观测值一致(至少在理论上)

我在这里没有看到什么? 提前感谢您的帮助

编辑:
值得一提的是,对“activeSupplier”可观察订阅的任何新订阅都会返回“null”,因为它是第一个值(即使在供应商的第二个console.log之后)

阅读您的评论和其中的代码,我想您可以试试这样的方法

首先,您将从http服务收到的活动供应商的值保存在某个地方,可能是在开始时。像这样的

export class SupplierService {
  activeSupplier = new BehaviorSubject<Supplier>(null);
  activeSupplierValue: Supplier;

  constructor (
    private http: HttpClient,
    private userService: UserService,
  ) {}
...

getOneSupplier(supplierId: string) {
  this.http.get<Supplier>(`${BASEURL}supplier/${supplierId}`)
    .subscribe(supplier => {
        this.activeSupplierValue = supplier;  // save the data of the active supplier
        ......
    });
  });
}
...

}

阅读您的评论和其中的代码,我认为您可以尝试类似的方法

首先,您将从http服务收到的活动供应商的值保存在某个地方,可能是在开始时。像这样的

export class SupplierService {
  activeSupplier = new BehaviorSubject<Supplier>(null);
  activeSupplierValue: Supplier;

  constructor (
    private http: HttpClient,
    private userService: UserService,
  ) {}
...

getOneSupplier(supplierId: string) {
  this.http.get<Supplier>(`${BASEURL}supplier/${supplierId}`)
    .subscribe(supplier => {
        this.activeSupplierValue = supplier;  // save the data of the active supplier
        ......
    });
  });
}
...

}
我找到了! 在多次调试日志之后,我发现我确实在创建该服务的另一个实例。为了找到答案,我登录了Supplier.service.ts构造函数。然后我看到两个日志在不同的行中发生。打开那些文件(chrome inspect>source),我发现它们是不同的(?),所以我尝试在Sockets.service.ts中“重写”导入,结果成功了

这是因为我错误地导入了它(末尾有一个“.js”)

由此:

import { UserService } from './User.service.js';
import { SupplierService } from './Supplier.service.js';
为此:

import { UserService } from './User.service';
import { SupplierService } from './Supplier.service';
现在一切都很好

我找到了! 在多次调试日志之后,我发现我确实在创建该服务的另一个实例。为了找到答案,我登录了Supplier.service.ts构造函数。然后我看到两个日志在不同的行中发生。打开那些文件(chrome inspect>source),我发现它们是不同的(?),所以我尝试在Sockets.service.ts中“重写”导入,结果成功了

这是因为我错误地导入了它(末尾有一个“.js”)

由此:

import { UserService } from './User.service.js';
import { SupplierService } from './Supplier.service.js';
为此:

import { UserService } from './User.service';
import { SupplierService } from './Supplier.service';

现在一切都很好

我明白了,您已经在根目录中注入了服务,您是否有可能在功能模块中提供服务?因为这可能会导致为该模块下的组件创建该服务的单独实例。因为我对Angular非常陌生,我只有一个模块(app.module.ts),它没有提供任何服务-顺便检查一下。文件中甚至没有他们的参考。所有服务都提供有“@Injectable({providedIn:'root'})”。我还应该找别的地方吗?也许我只是不知道“在功能模块中提供服务”可能在哪里。请参阅此文档。您的服务实例创建和单例服务范围基于您提供服务的方式。@PushpikaWan我已经检查了此文档,这就是我在代码中遵循的内容。我的所有服务都在它们自己的文件中以“@Injectable({providedIn:'root'})”提供,其他任何地方都不提供它们。我刚刚检查了整个项目文件夹中的Visual Studio代码搜索,在它自己的文件(对于“root”)之外没有提供任何内容:(
updateSupplierList
在做什么?似乎
updateSupplierList
是套接字收到消息时调用的方法。我知道,您已将服务注入根目录,是否有可能在功能模块中提供服务?因为这可能会导致创建单独的实例由于我对Angular非常陌生,所以我只有一个模块(app.module.ts),没有提供任何服务,只是顺便检查了一下。文件中甚至没有对它们的引用。所有服务都提供了“@Injectable({providedIn:'root'})”.我还应该找其他地方吗?也许我只是不知道这个“在功能模块中提供服务”的地方可能在中。请参阅此文档。您的服务实例创建和单例服务范围基于您提供服务的方式。@PushpikaWan我已经检查了此文档,这就是我在代码中遵循的内容。我的所有服务都在自己的文件中提供,并带有“@Injectable({providedIn:'root'})”其他任何地方都没有提供它们。我刚刚检查了整个项目文件夹中的Visual Studio代码搜索,在它自己的文件(对于“root”)之外没有提供任何内容:(updateSupplierList在做什么?当套接字重新启动时,似乎调用了updateSupplierList方法