He leído que la inyección cuando el bootstrapping debería hacer que todos los niños compartan la misma instancia, pero mis componentes principal y de encabezado (la aplicación principal incluye el componente de encabezado y la salida del enrutador) obtienen cada uno una instancia separada de mis servicios.
Tengo un FacebookService que utilizo para realizar llamadas a la API de Facebook JavaScript y un UserService que utiliza el FacebookService. Aquí está mi bootstrap:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
Desde mi registro, parece que finaliza la llamada de arranque, luego veo que se crea FacebookService y luego UserService antes de que se ejecute el código en cada uno de los constructores, MainAppComponent, HeaderComponent y DefaultComponent:
angular
typescript
angular2-routing
angular2-services
Jason Goemaat
fuente
fuente
UserService
yFacebookService
enproviders
ningún otro lugar?Respuestas:
Jason tiene toda la razón! Es causado por la forma en que funciona la inyección de dependencia. Se basa en inyectores jerárquicos.
Hay varios inyectores dentro de una aplicación Angular2:
Cuando Angular2 intenta inyectar algo en el constructor de componentes:
Por lo tanto, si desea tener un singleton para toda la aplicación, debe tener el proveedor definido a nivel del inyector raíz o del inyector del componente de la aplicación.
Pero Angular2 mirará el árbol del inyector desde la parte inferior. Esto significa que se utilizará el proveedor en el nivel más bajo y el alcance de la instancia asociada será este nivel.
Vea esta pregunta para más detalles:
fuente
Actualización (Angular 6 +)
La forma recomendada de crear un servicio singleton ha cambiado. Ahora se recomienda especificar en el
@Injectable
decorador del servicio que se debe proporcionar en la 'raíz'. Esto tiene mucho sentido para mí y ya no es necesario enumerar todos los servicios proporcionados en sus módulos. Solo importa los servicios cuando los necesita y se registran en el lugar adecuado. También puede especificar un módulo para que solo se proporcione si se importa el módulo.Actualización (Angular 2)
Con NgModule, creo que la forma de hacerlo ahora es crear un 'CoreModule' con su clase de servicio y enumerar el servicio en los proveedores del módulo. Luego importa el módulo central en el módulo de la aplicación principal que proporcionará la única instancia a los niños que soliciten esa clase en sus constructores:
CoreModule.ts
AppModule.ts
Respuesta original
Si incluye un proveedor
bootstrap()
, no necesita incluirlo en su decorador de componentes:De hecho, la inclusión de su clase en 'proveedores' crea una nueva instancia de la misma, si algún componente principal ya lo incluye, los hijos no necesitan hacerlo y, si lo hacen, obtendrán una nueva instancia.
fuente
[providers]
en su archivo de módulo, no enbootstrap()
, ¿verdad?ApiService
enAppModule
'sproviders
, y así evitar la necesidad deCoreModule
? (No estoy seguro de que esto sea lo que sugiere @JasonSwett).ApiService
en la parte superior, pero ¿por qué molestarse en ponerlo en la matriz de proveedores de CoreModule y luego importarlo en app.module ... todavía no hizo clic para mí?TestService
se especifica en los módulos principales y de la aplicación, las instancias no se crean para los módulos porque es proporcionado por el componente, por lo que angular nunca llega tan alto en el árbol del inyector. Entonces, si proporciona un servicio en su módulo y nunca lo usa, parece que no se crea una instancia.Sé que angular tiene inyectores jerárquicos, como dijo Thierry.
Pero tengo otra opción aquí en caso de que encuentre un caso de uso en el que realmente no desee inyectarlo en el padre.
Podemos lograr eso mediante la creación de una instancia del servicio, y en proporcionar siempre devolver eso.
Y luego, en su componente, utiliza su método de suministro personalizado.
Y debe tener un servicio único sin depender de los inyectores jerárquicos.
No digo que esta sea una mejor manera, es solo en caso de que alguien tenga un problema donde los inyectores jerárquicos no sean posibles.
fuente
SHARE_SERVICE_PROVIDER
estarYOUR_SERVICE_PROVIDER
en el componente? También supongo que la importación del archivo de servicio es necesaria como normal y el constructor seguirá teniendo un parámetro de tipo 'YourService', ¿verdad? Creo que me gusta, le permite garantizar un singleton y no tener que asegurarse de que el servicio se brinde en la jerarquía. También permite que los componentes individuales obtengan su propia copia simplemente enumerando el servicio enproviders
lugar del proveedor único, ¿verdad?YOUR_SERVICE_PROVIDER
. Sí, todos los componentes obtendrán la misma instancia simplemente agregándola en los proveedores.instance
propiedad en un mapa de instancias de valores claveLa sintaxis ha sido modificada. Mira este enlace
Las dependencias son singletons dentro del alcance de un inyector. En el siguiente ejemplo, se comparte una sola instancia de HeroService entre HeroesComponent y sus hijos HeroListComponent.
Paso 1. Crea una clase singleton con el decorador @Injectable
Paso 2. Inyectar en el constructor
Paso 3. Registrar proveedor
fuente
Injectable
pasa si mi clase no es un servicio y solo contienestatic
cadenas para uso global?Agregar
@Injectable
decorador al Servicio Y registrarlo como proveedor en el Módulo raíz lo convertirá en un singleton.fuente
constructor
siguiente manera:import { SomeService } from '../../services/some/some'; @Component({ selector: 'page-selector', templateUrl: 'page.html', }) export class SomePage { constructor( public someService: SomeService ) { }
esto parece estar funcionando bien para mí
fuente
Aquí hay un ejemplo de trabajo con Angular versión 2.3. Simplemente llame al constructor del servicio de manera similar a este constructor (private _userService: UserService). Y creará un singleton para la aplicación.
user.service.ts
app.component.ts
fuente
UNA
singleton service
es un servicio para el que solo existe una instancia en una aplicación.Hay (2) formas de proporcionar un servicio singleton para su aplicación.
usar la
providedIn
propiedad, oproporcionar el módulo directamente en
AppModule
la aplicaciónUsando provideIn
Comenzando con Angular 6.0, la forma preferida de crear un servicio singleton es establecer la
providedIn
raíz en el@Injectable()
decorador del servicio . Esto le dice a Angular que proporcione el servicio en la raíz de la aplicación.Matriz de proveedores de NgModule
En las aplicaciones creadas con versiones angulares anteriores a 6.0, los servicios son matrices de proveedores de NgModule registradas de la siguiente manera:
Si esta
NgModule
fuera la raízAppModule
, UserService sería un singleton y estaría disponible en toda la aplicación. Aunque puede verlo codificado de esta manera, es preferible utilizar laprovidedIn
propiedad del@Injectable()
decorador en el servicio en sí mismo a partir de Angular 6.0, ya que hace que sus servicios sean inestables.fuente
Puedes usar
useValue
en proveedoresfuente
useValue
no está relacionado con singleton. Usevalue es solo para pasar un valor en lugar de unType
(useClass
) que DI llamanew
ouseFactory
donde se pasa una función que devuelve el valor cuando DI lo llama. Angular DI mantiene una única instancia por proveedor automáticamente. Solo proporcione una vez y tendrá un singleton. Lo siento, tengo que votar a favor porque es información no válida: - /Desde Angular @ 6, puede tener
providedIn
en unInjectable
.Consulta los documentos aquí
fuente
public static
.Simplemente declare su servicio como proveedor solo en app.module.ts.
Hizo el trabajo por mí.
luego instanciarlo usando un parámetro privado del constructor:
o ya que si su servicio se usa desde html, la opción -prod reclamará:
agregue un miembro para su servicio y llénelo con la instancia recibida en el constructor:
fuente
Si desea hacer que el servicio sea único a nivel de aplicación, debe definirlo en app.module.ts
proveedores: [MyApplicationService] (también puede definir lo mismo en el módulo secundario para que sea específico de ese módulo)
Si desea definir el servicio singleton a nivel de componente, cree el servicio, agregue ese servicio en app.module.ts y agregue la matriz de proveedores dentro del componente específico como se muestra en el siguiente fragmento.
@Component ({selector: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], proveedores: [TestMyService]})
Angular 6 proporciona una nueva forma de agregar servicio a nivel de aplicación. En lugar de agregar una clase de servicio a la matriz de proveedores [] en AppModule, puede establecer la siguiente configuración en @Injectable ():
@Injectable ({shownIn: 'root'}) clase de exportación MyService {...}
Sin embargo, la "nueva sintaxis" ofrece una ventaja: Angular (detrás de escena) puede cargar los servicios con pereza y eliminar automáticamente el código redundante. Esto puede conducir a un mejor rendimiento y velocidad de carga, aunque esto realmente solo se aplica a servicios y aplicaciones más grandes en general.
fuente
Además de las excelentes respuestas anteriores, puede faltar algo más si las cosas en su singleton aún no se comportan como un singleton. Me encontré con el problema cuando llamé a una función pública en el singleton y descubrí que estaba usando las variables incorrectas. Resulta que el problema era
this
que no se garantiza que esté vinculado al singleton para ninguna función pública en el singleton. Esto se puede corregir siguiendo los consejos aquí , así:Alternativamente, puede simplemente declarar los miembros de la clase como en
public static
lugar depublic
, luego el contexto no importará, pero tendrá que acceder a ellos como enSubscriptableService.onServiceRequested$
lugar de usar la inyección de dependencia y acceder a ellos a través dethis.subscriptableService.onServiceRequested$
.fuente
Servicios para padres e hijos.
Estaba teniendo problemas con un servicio para padres y su hijo usando diferentes instancias. Para forzar el uso de una instancia, puede alias al padre con referencia al hijo en los proveedores del módulo de la aplicación. El padre no podrá acceder a las propiedades del niño, pero se usará la misma instancia para ambos servicios. https://angular.io/guide/dependency-injection-providers#aliased-class-providers
app.module.ts
Servicios utilizados por componentes fuera del alcance de los módulos de su aplicación
Al crear una biblioteca que consta de un componente y un servicio, me encontré con un problema en el que se crearían dos instancias. Uno por mi proyecto angular y otro por el componente dentro de mi biblioteca. La solución:
my-outside.component.ts
my-inside.component.ts
my-inside.component.hmtl
fuente