Compartir a través de


ServiceScope class

Patrón de localizador de servicios que usa el SharePoint Framework.

Comentarios

ServiceScope proporciona una forma formalizada para que los componentes registren y consuman dependencias ("servicios"), y para permitir que diferentes implementaciones se registren en ámbitos diferentes. Esto mejora la modularidad al desacoplar los componentes de sus dependencias de forma extensible.

Por ejemplo, supongamos que varios componentes necesitan acceso a una instancia de IPageManager. Simplemente podríamos convertir el PageManager en un singleton (es decir, una variable global), pero esto no funcionará, por ejemplo, si necesitamos crear un cuadro de diálogo emergente que requiera una segunda instancia de PageManager. Una solución mejor sería agregar PageManager como parámetro de constructor para cada componente que lo requiera, pero entonces nos enfrentamos inmediatamente al problema de que cualquier código que llame a estos constructores también necesita un parámetro PageManager. En una aplicación con muchas de estas dependencias, la lógica de negocios que une muchos subsistemas finalmente elegiría un parámetro de constructor para cada dependencia posible, lo que resulta incómodo. Una solución natural sería mover todas las dependencias a una clase con el nombre "ApplicationContext" y, a continuación, pasar esto como parámetro del constructor. Esto permite pasar el PageManager a las clases que lo necesitan sin saturar las clases intermedias que no lo hacen. Sin embargo, sigue teniendo un problema de diseño que indica que "ApplicationContext" tiene dependencias codificadas de forma rígida en muchas cosas no relacionadas. Un enfoque más flexible consiste en convertirlo en un diccionario que pueda buscar elementos para consumidores o proveedores que conozcan la clave de búsqueda adecuada (es decir, ServiceKey). Este es el patrón de diseño popular de "localizador de servicios", conocido por la API de SPContext en SharePoint clásico.

ServiceScope lleva esta idea un paso más allá de dos maneras importantes: en primer lugar, proporciona un mecanismo de ámbito para que, por ejemplo, si tenemos dos páginas diferentes, cada una de ellas pueda proporcionar una instancia única de PageManager mientras se comparten otras dependencias comunes. En segundo lugar, permite que servicekey proporcione una implementación predeterminada de la dependencia. Esto es importante para la estabilidad de la API en nuestro entorno modular del lado cliente: por ejemplo, supongamos que la versión 2.0 de nuestra aplicación introdujo una nueva interfaz IDiagnosticTracing que un componente de la versión 2.0 espera consumir. Si el componente de la versión 2.0 se carga mediante una aplicación 1.0 anterior, se producirá un error. Podríamos corregir esto exigiendo a cada consumidor que compruebe si faltan dependencias y controle ese caso, pero requeriría muchas comprobaciones. Una mejor solución es asegurarse de que siempre existe una implementación predeterminada, quizás solo un comportamiento trivial, para que los componentes puedan suponer que consume() siempre devolverá algún objeto que implemente el contrato.

Uso: las instancias de ServiceScope se crean llamando a ServiceScope.startNewRoot() o ServiceScope.startNewChild(). Inicialmente están en un estado "inacabado", durante el cual se puede llamar a provide() para registrar las claves de servicio, pero consume() no está permitido. Después de llamar a ServiceScope.finish(), se permite consume() y provide() ahora no está permitido. Esta semántica garantiza que ServiceScope.consume() siempre devuelve el mismo resultado para la misma clave y no depende del orden de inicialización. También nos permite admitir dependencias circulares sin preocuparnos por bucles infinitos. (Las dependencias circulares se evitan mejor, pero esto es difícil de garantizar cuando se trabaja con componentes que fueron aportados por varios terceros sin ninguna coordinación). Para evitar errores, es mejor llamar siempre a consume() dentro de una devolución de llamada desde serviceScope.whenFinished().

Constructores

(constructor)(parent)

Construye una nueva instancia de la ServiceScope clase

Métodos

consume(serviceKey)

Consume un servicio desde el ámbito del servicio.

createAndProvide(serviceKey, simpleServiceClass)

Se trata de una función abreviada que equivale a construir una nueva instancia de simpleServiceClass y, a continuación, registrarla llamando a ServiceScope.provide().

createDefaultAndProvide(serviceKey)

Se trata de una función abreviada que construye la implementación predeterminada del parámetro serviceKey especificado y, después, la registra mediante una llamada a ServiceScope.provide().

finish()

Completa la secuencia de inicialización de un ámbito de servicio.

getParent()

Devuelve el objeto primario del ServiceScope actual o undefined si se trata de un ámbito raíz.

provide(serviceKey, service)

Agregue un nuevo servicio a un ámbito de servicio.

startNewChild()

Construye un ServiceScope nuevo que es un elemento secundario del ámbito actual.

startNewRoot()

Crear un ServiceScope de nivel raíz. Solo los ámbitos de nivel raíz pueden crear automáticamente implementaciones predeterminadas de ServiceKey.

whenFinished(callback)

Aplazar una operación hasta que se haya completado ServiceScope.finish().

Detalles del constructor

(constructor)(parent)

Construye una nueva instancia de la ServiceScope clase

protected constructor(parent: ServiceScope | undefined);

Parámetros

parent

ServiceScope | undefined

Detalles del método

consume(serviceKey)

Consume un servicio desde el ámbito del servicio.

consume<T>(serviceKey: ServiceKey<T>): T;

Parámetros

serviceKey

ServiceKey<T>

Clave que se usó cuando se llamó a provide() para registrar el servicio.

Devoluciones

T

Instancia de servicio

Comentarios

Los componentes deben llamar a esta función para "consumir" una dependencia, es decir, buscar el parámetro serviceKey y devolver la instancia del servicio registrado. Si no se encuentra la instancia, se creará y registrará automáticamente una instancia predeterminada con el ServiceScope raíz.

createAndProvide(serviceKey, simpleServiceClass)

Se trata de una función abreviada que equivale a construir una nueva instancia de simpleServiceClass y, a continuación, registrarla llamando a ServiceScope.provide().

createAndProvide<T>(serviceKey: ServiceKey<T>, simpleServiceClass: {
        new (serviceScope: ServiceScope): T;
    }): T;

Parámetros

serviceKey

ServiceKey<T>

Clave que se puede emplear más adelante para usar el servicio.

simpleServiceClass

{ new (serviceScope: ServiceScope): T; }

Clase TypeScript que se va a construir.

Devoluciones

T

Instancia recién construida de simpleServiceClass.

createDefaultAndProvide(serviceKey)

Se trata de una función abreviada que construye la implementación predeterminada del parámetro serviceKey especificado y, después, la registra mediante una llamada a ServiceScope.provide().

createDefaultAndProvide<T>(serviceKey: ServiceKey<T>): T;

Parámetros

serviceKey

ServiceKey<T>

Clave que se puede emplear más adelante para usar el servicio.

Devoluciones

T

Instancia de servicio que se construyó mediante ServiceKey.defaultCreator

finish()

Completa la secuencia de inicialización de un ámbito de servicio.

finish(): void;

Devoluciones

void

Comentarios

Cuando se inicia un ServiceScope por primera vez, se encuentra en un estado "inacabado", donde se permite provide(), pero consume() no está permitido. Después de llamar a finish(), se permite consume(), pero provide() no está permitido.

Este formalismo evita una serie de situaciones complejas que podrían provocar errores. Por ejemplo, se supone que Scope2 es un elemento secundario de Scope1 y Scope1 proporciona la instancia A1 de la interfaz A. Si alguien consume A1 desde Scope2 (mediante herencia) antes de llamar a Scope2.provide() con A2, una llamada posterior a Scope2.consume() podría devolver un resultado diferente al de la llamada anterior. Este nondeterminismo podría provocar resultados imprevisibles difíciles de diagnosticar.

getParent()

Devuelve el objeto primario del ServiceScope actual o undefined si se trata de un ámbito raíz.

getParent(): ServiceScope | undefined;

Devoluciones

ServiceScope | undefined

Ámbito de servicio primario.

provide(serviceKey, service)

Agregue un nuevo servicio a un ámbito de servicio.

provide<T>(serviceKey: ServiceKey<T>, service: T): T;

Parámetros

serviceKey

ServiceKey<T>

Clave que se empleará más adelante para usar el servicio.

service

T

Instancia de servicio que se está registrando.

Devoluciones

T

El mismo objeto que se pasó como parámetro de "servicio".

Comentarios

ServiceScope.provide() se usa para registrar una implementación de serviceKey determinada para el ámbito actual y una implementación de un rootServiceKey determinado para el ámbito raíz. Solo se puede usar cuando ServiceScope se encuentra en un estado "sin terminar", es decir, antes de llamar a finish().

startNewChild()

Construye un ServiceScope nuevo que es un elemento secundario del ámbito actual.

startNewChild(): ServiceScope;

Devoluciones

ServiceScope raíz recién creado.

Comentarios

Los ámbitos de servicio forman una estructura de árbol, de modo que al consumir un servicio, si un ámbito secundario no proporciona explícitamente la clave, se consultará a la jerarquía primaria.

startNewRoot()

Crear un ServiceScope de nivel raíz. Solo los ámbitos de nivel raíz pueden crear automáticamente implementaciones predeterminadas de ServiceKey.

static startNewRoot(): ServiceScope;

Devoluciones

ServiceScope raíz recién creado.

whenFinished(callback)

Aplazar una operación hasta que se haya completado ServiceScope.finish().

whenFinished(callback: () => void): void;

Parámetros

callback

() => void

Bloque de código que necesita llamar a ServiceScope.consume().

Devoluciones

void

Comentarios

Es un error llamar a ServiceScope.consume() antes de que se haya llamado a finish(). La manera más confiable de proteger el componente frente a este error es realizar las llamadas consume() dentro de una devolución de llamada whenFinished(). Si el ámbito del servicio ya ha finalizado, la devolución de llamada se ejecutará inmediatamente; De lo contrario, se ejecutará más adelante cuando finalice el ámbito.

NOTA: No se trata de una devolución de llamada asincrónica. La inicialización de ServiceScope suele ser económica y de corta duración. Sin embargo, el flujo de control suele pasar por numerosos constructores y clases base, que se pueden simplificar mediante whenFinished().