Compartilhar via


ServiceScope class

O padrão de localizador de serviço usado pelo Estrutura do SharePoint.

Comentários

O ServiceScope proporciona uma maneira formal para os componentes registrarem e consumirem dependências ("serviços") e habilitar implementações diferentes para serem registradas em diferentes escopos. Isso melhora a modularidade por meio da separação de componentes de suas dependências de forma extensível.

Por exemplo, suponha que vários componentes precisem ter acesso a uma instância do PageManager. Poderíamos simplesmente tornar o PageManager único (ou seja, variável global), mas isso não funcionará, por exemplo, se for necessário criar uma caixa de diálogo pop-up que exija uma segunda instância do PageManager. Uma solução melhor seria adicionar o PageManager como um parâmetro de construtor para cada componente que precise dele; no entanto, em seguida, encontramos imediatamente o problema que qualquer código que chame esses construtores também precisam de um parâmetro PageManager. Em um aplicativo com muitas dessas dependências, a lógica de negócios que une muitos subsistemas eventualmente pegaria um parâmetro de construtor para cada dependência possível, o que é estranho. Uma solução natural seria mover todas as dependências para uma classe com nome como "ApplicationContext" e, em seguida, utilizar como nosso parâmetro de construtor. Isso permite que o PageManager seja passado para classes que precisam dele sem encher as classes intermediárias que não precisam. No entanto, ainda há um problema de design que "ApplicationContext" tem dependências embutidas em muitas coisas não relacionadas. É uma abordagem mais flexível para torná-lo um dicionário que pode pesquisar itens para os consumidores/provedores que saibam a chave de pesquisa certa (ou seja, ServiceKey). Este é o padrão de design de "localizador de serviço" popular, familiar da API SPContext no SharePoint clássico.

O ServiceScope leva essa ideia um passo adiante de duas maneiras importantes: primeiro, ela fornece um mecanismo de escopo para que, por exemplo, se tivermos duas páginas diferentes, cada uma delas poderá fornecer uma instância exclusiva do PageManager enquanto ainda compartilha outras dependências comuns. Em segundo lugar, ele permite que um ServiceKey forneça uma implementação padrão da dependência. Isso é importante para a estabilidade da API em nosso ambiente modular do lado do cliente: Por exemplo, suponha que a versão 2.0 do nosso aplicativo introduziu uma nova interface do IDiagnosticTracing que um componente de versão 2.0 espera consumir. Se o componente de versão 2.0 for carregado por um aplicativo 1.0 mais antigo, ele falhará. Nós podemos corrigir isso exigindo que cada consumidor verifique se há dependências faltando e administrar esse caso, mas isso exigiria muitas verificações. Uma solução melhor é garantir que uma implementação padrão sempre exista, talvez apenas um comportamento trivial, para que os componentes possam assumir que consumir() sempre retornará algum objeto que implemente o contrato.

Uso: As instâncias de ServiceScope são criadas chamando ServiceScope.startNewRoot() ou ServiceScope.startNewChild(). Inicialmente, eles estão em um estado "inacabado", durante o qual o fornece() pode ser chamado para registrar chaves de serviço, mas consumir() não é permitido. Depois que ServiceScope.finish() for chamado, consumir() é permitido e fornecer() agora é permitido. Essa semântica garante que ServiceScope.consume() sempre retorne o mesmo resultado para a mesma chave e não dependa da ordem de inicialização. Ele também nos permite dar suporte a dependências circulares sem se preocupar com loops infinitos. (As dependências circulares são melhor evitadas, no entanto, isso é difícil de garantir ao trabalhar com componentes que foram contribuídos por vários terceiros sem qualquer coordenação.) Para evitar erros, é melhor sempre chamar consum() dentro de um retorno de chamada do serviceScope.whenFinished().

Construtores

(constructor)(parent)

Constrói uma nova instância da ServiceScope classe

Métodos

consume(serviceKey)

Consome um serviço do escopo do serviço.

createAndProvide(serviceKey, simpleServiceClass)

Essa é uma função abreviada equivalente à construção de uma nova instância do simpleServiceClass e, em seguida, registrá-la chamando ServiceScope.provide().

createDefaultAndProvide(serviceKey)

Essa é uma função abreviada que constrói a implementação padrão do ServiceKey especificado e registra-o chamando ServiceScope.provide().

finish()

Conclui a sequência de inicialização de um escopo de serviço.

getParent()

Retorna o pai do ServiceScope atual ou indefinido se este for um escopo de raiz.

provide(serviceKey, service)

Adicione um novo serviço a um escopo de serviço.

startNewChild()

Cria um novo ServiceScope que é um filho do escopo atual.

startNewRoot()

Crie um novo ServiceScope de nível raiz. Somente os escopos de nível raiz têm a capacidade de criar automaticamente implementações padrão de ServiceKeys.

whenFinished(callback)

Adie uma operação até que ServiceScope.finish() seja concluída.

Detalhes do construtor

(constructor)(parent)

Constrói uma nova instância da ServiceScope classe

protected constructor(parent: ServiceScope | undefined);

Parâmetros

parent

ServiceScope | undefined

Detalhes do método

consume(serviceKey)

Consome um serviço do escopo do serviço.

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

Parâmetros

serviceKey

ServiceKey<T>

a chave que foi usada quando provide() foi chamado para registrar o serviço

Retornos

T

a instância do serviço

Comentários

Os componentes devem chamar esta função para "consumir" uma dependência, ou seja, procurar o serviceKey e retornar a instância do serviço registrado. Se a instância não puder ser encontrada, uma instância padrão será criada automaticamente e registrada com o ServiceScope raiz.

createAndProvide(serviceKey, simpleServiceClass)

Essa é uma função abreviada equivalente à construção de uma nova instância do simpleServiceClass e, em seguida, registrá-la chamando ServiceScope.provide().

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

Parâmetros

serviceKey

ServiceKey<T>

a chave que pode ser usada posteriormente para consumir o serviço

simpleServiceClass

{ new (serviceScope: ServiceScope): T; }

a classe TypeScript a ser construída

Retornos

T

uma instância de simpleServiceClass construída recentemente

createDefaultAndProvide(serviceKey)

Essa é uma função abreviada que constrói a implementação padrão do ServiceKey especificado e registra-o chamando ServiceScope.provide().

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

Parâmetros

serviceKey

ServiceKey<T>

a chave que pode ser usada posteriormente para consumir o serviço

Retornos

T

uma instância do serviço que foi construída usando ServiceKey.defaultCreator

finish()

Conclui a sequência de inicialização de um escopo de serviço.

finish(): void;

Retornos

void

Comentários

Quando um ServiceScope é iniciado pela primeira vez, ele está em um estado "inacabado" em que o fornece() é permitido, mas o consumo() é não permitido. Depois de chamar finish(), em seguida, consuma() é permitido, mas fornecer() é não permitido.

Esse formalismo impede uma série de situações complexas que podem levar a bugs. Por exemplo, suponha que o Scope2 seja filho do Scope1 e o Scope1 fornece a instância A1 da interface A. Se alguém consumir A1 do Scope2 (via herança) antes que Scope2.provide() seja chamado com A2, uma chamada subsequente para Scope2.consum() poderá retornar um resultado diferente da chamada anterior. Esse nãodeterminismo pode causar resultados imprevisíveis difíceis de diagnosticar.

getParent()

Retorna o pai do ServiceScope atual ou indefinido se este for um escopo de raiz.

getParent(): ServiceScope | undefined;

Retornos

ServiceScope | undefined

o escopo do serviço pai

provide(serviceKey, service)

Adicione um novo serviço a um escopo de serviço.

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

Parâmetros

serviceKey

ServiceKey<T>

a chave que será usada mais tarde para consumir o serviço

service

T

a instância do serviço que está sendo registrada

Retornos

T

o mesmo objeto que foi passado como o parâmetro "service"

Comentários

ServiceScope.provide() é usado para registrar uma implementação do serviceKey fornecido para o escopo atual e uma implementação de um determinado rootServiceKey para o escopo raiz. Só pode ser usado quando o ServiceScope estiver em um estado "não concluído", ou seja, antes de finish() ter sido chamado.

startNewChild()

Cria um novo ServiceScope que é um filho do escopo atual.

startNewChild(): ServiceScope;

Retornos

o ServiceScope raiz recém-criado

Comentários

Os escopos de serviço formam uma estrutura de árvore, de modo que, ao consumir um serviço, se a chave não for fornecida explicitamente por um escopo filho, a hierarquia pai será consultada.

startNewRoot()

Crie um novo ServiceScope de nível raiz. Somente os escopos de nível raiz têm a capacidade de criar automaticamente implementações padrão de ServiceKeys.

static startNewRoot(): ServiceScope;

Retornos

o ServiceScope raiz recém-criado

whenFinished(callback)

Adie uma operação até que ServiceScope.finish() seja concluída.

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

Parâmetros

callback

() => void

Um bloco de código que precisa chamar ServiceScope.consume()

Retornos

void

Comentários

É um erro para chamar ServiceScope.consume() antes de ter chamado finish(). A maneira mais confiável para proteger seu componente contra esse erro é executar as chamadas consume() dentro de um retorno de chamada whenFinished(). Se o escopo do serviço já estiver concluído, o retorno de chamada será executado imediatamente; caso contrário, ele será executado posteriormente quando o escopo tiver sido concluído.

OBSERVAÇÃO: este não é um retorno de chamada assíncrono. A inicialização do ServiceScope normalmente é barata e de curta duração. No entanto, o fluxo de controle geralmente passa por vários construtores e classes base, o que pode ser simplificado usando whenFinished().