npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fn-context

v0.2.61

Published

O `fn-context` é um pacote que fornece um contexto de execução para funções no Node.js. Ele é útil para funções que precisam de um contexto de execução, como funções que precisam de um contexto de banco de dados, funções que precisam de um contexto de aut

Downloads

1,199

Readme

fn-context

O fn-context é um pacote que fornece um contexto de execução para funções no Node.js. Ele é útil para funções que precisam de um contexto de processo. Ou seja, não importa o quão profundo você chame uma função, o contexto de execução será o mesmo para cada processo de forma individual. O contexto é usado para gerenciar dados globais, por exemplo, estado global, serviços, configurações de usuário e muito mais.

Índice

Como usar o contexto

Usar o contexto no fn-context requer 3 etapas simples: criar o contexto, fornecer o contexto e consumir o contexto.

1. Criando o contexto

A função de fábrica integrada createContext(default) cria uma instância de contexto:

// context.js
import { createContext } from 'react';

export const Context = createContext('Default Value');

A função de fábrica aceita um argumento opcional: o valor padrão. Se você não fornecer um valor padrão, o valor padrão será undefined.

2. Fornecendo o contexto

A propriedade provider disponível na instância de contexto é usado para fornecer o contexto para as funções chamadas no escopo, não importa quão profundos eles estejam.

É uma função que requer dois argumentos:

  • target: a função que será executada.
  • defaultValue: o valor padrão do contexto para a função target, argumento opcional. Se não for definido, o valor padrão do contexto será o valor definido no createContext.
// index.js
import { Context } from './context';

const fn = async () => {
  console.log(Context.get()); // 'Default Value'
};

await Context.provider(fn)();

O que é importante aqui é que todos as funções que desejam consumir o contexto mais tarde devem estar envoltos dentro do escopo provider.

3. Consumindo o contexto

Consumir o contexto pode ser feito de 2 maneiras.

A primeira maneira recomendada, é usar a propriedade get disponível na instância de contexto:

// index.js
import { Context } from './context';

const fn = async () => {
  console.log(Context.get()); // 'Default Value'
};

await Context.provider(fn)();

A segunda maneira é usar a propriedade value disponível na instância de contexto:

// index.js
import { Context } from './context';

const fn = async () => {
  console.log(Context.value); // 'Default Value'
};

await Context.provider(fn)();

Em caso que deseja alterar o valor do contexto, você pode usar a propriedade set disponível na instância de contexto, ou, mudar diretamente o valor da propriedade value:

// index.js
import { Context } from './context';

const fn = async () => {
  Context.set('New Value');
  // ou
  // Context.value = 'New Value';
  console.log(Context.get()); // 'New Value'
};

await Context.provider(fn)();

npm

Você pode ter quantos consumidores quiser para um único contexto. Se o valor do contexto mudar (alterando a propriedade value na instância de contexto), todos os consumidores recebem o valor atualizado. Se o valor do contexto mudar dentro de um consumidor, todos os outros consumidores recebem o valor atualizado.

Se o consumidor não estiver envolto dentro do provedor, mas ainda tentar acessar o valor do contexto, então o valor do contexto será o valor padrão fornecido como argumento para a função fábrica createContext(defaultValue) que criou o contexto.

Quando você precisa de contexto?

A principal ideia de usar o contexto é permitir que seus processos acessem dados globais e repassem quando esses dados globais forem alterados. O contexto resolve o problema de perfuração de props: quando você precisa passar props dos pais para os filhos.

Você pode manter dentro do contexto:

  • estado global
  • configuração da aplicação
  • nome do usuário autenticado
  • configurações do usuário
  • idioma preferido
  • uma coleção de serviços
  • ... e muito mais

Por outro lado, você deve pensar cuidadosamente antes de decidir usar contexto em sua aplicação.

Primeiro, integrar o contexto adiciona complexidade. Criar um contexto, envolver tudo em um provedor e usar value em cada consumidor — aumenta a complexidade.

Em segundo lugar, adicionar contexto complica o teste unitário dos processos. Durante os testes, você terá que envolver as funções consumidores em um provedor de contexto. Incluindo as funções que são afetados indiretamente pelo contexto — os ancestrais dos consumidores de contexto!

Imagine-se uma situação onde você tem uma função que precisa de um contexto unificado para cada processo de forma individual. O fn-context permite que você defina um contexto de execução para cada função e fornece uma maneira de acessar esse contexto de execução em qualquer lugar da função ou qualquer outra função que você chame dentro do escopo do contexto inicializado anteriormente, como o context.provider.

Exemplo:

import { createContext } from 'fn-context';

const context = createContext();

const fn = async () => {
  const fn2 = async () => {
    console.log(context.get()); // { foo: 'bar' }
  };

  await fn2();
};

await context.provider(fn, { foo: 'bar' })();

Neste exemplo, a função fn2 acessa o contexto de execução definido pela função fn. Isso é útil quando você precisa de um contexto de execução unificado para cada função.

Também funciona em caso de funções aninhadas:

import { createContext } from 'fn-context';

const context = createContext();

const fn = async () => {
  const fn2 = async () => {
    const fn3 = async () => {
      console.log(context.get()); // { foo: 'bar' }
    };

    await fn3();
  };

  await fn2();
};

await context.provider(fn, { foo: 'bar' })();

Ou fora de escopo:

import { createContext } from 'fn-context';

const context = createContext();

const fn2 = async () => {
  console.log(context.get()); // { foo: 'bar' }
};

const fn = async () => {
  await fn2();
};

await context.provider(fn, { foo: 'bar' })();

Neste exemplo, a função fn2 acessa o contexto mesmo que não esteja dentro do escopo da função fn. Porém, esse método só funcionará se a função fn2 for chamada dentro do escopo da função fn onde foi definido o contexto com o uso do context.provider. Caso contrário, o contexto não será acessível e retornará o valor padrão pré-definido no createContext.

É importante que saiba que o contexto é definido apenas para a função que o inicializou. Se você chamar a função fn em outro lugar, o contexto não será acessível e/ou retornará o valor padrão pré-definido no createContext, como no exemplo abaixo:

import { createContext } from 'fn-context';

const context = createContext();

const fn = async () => {
  console.log(context.get());
};

await context.provider(fn, { foo: 'bar' })();
await fn(); // O contexto não será acessível

É possível realizar exportação e importação do contexto para outras funções:

// context.ts
import { createContext } from 'fn-context';
export const context = createContext();
// fn.ts
import { context } from './context';

export const fn2 = async () => {
  context.set({ foo: 'bar', bar: 'foo' });
};

export const fn3 = async ()=>{
  console.log(context.get()); // { foo: 'bar', bar: 'foo' }
}
// index.ts
import { context } from './context';
import { fn2, fn3 } from './fn';

const fn = context.provider(async () => {
  fn2();
  fn3();
}, { foo: 'bar' });

await fn();

É possível criar vários contextos de execução para a mesma função ou funções diferentes:

import { createContext } from 'fn-context';

const context1 = createContext();
const context2 = createContext();

const fn = async () => {
  console.log(context1.get()); // { foo: 'bar' }
  console.log(context2.get()); // { bar: 'foo' }
};

await context2.provider(context1.provider(fn, { foo: 'bar' }), { bar: 'foo' })();

Uma coisa que é preciso resaltar é que, contextualizando uma função, o que se espera é que, o valor do contexto seja único para cada processo iniciado. Ou seja, se você chamar a função fn duas vezes, o contexto será diferente para as duas chamadas. Isso é útil para funções que precisam de um contexto de execução unificado para cada processo de forma individual.

import { createContext } from 'fn-context';

const context = createContext({ foo: 'bar' });

const fn2 = async ()=>{
  const valor = context.get();
  context.set({...valor, time: Date.now()});
}

const fn3 = async ()=>{
  return context.get();
}

const fn = async ()=>{
  await fn2();
  return await fn3();
};

context.provider(fn)().then(console.log); // { foo: 'bar', time: 1633661600000 }
context.provider(fn, { bar: 'foo' })().then(console.log); // { bar: 'foo', time: 1633661601000 }

O fn-context foi pensado para uso de contextualização em desenvolvimento de APIs, inclusivemente, para o Express.js. Ou seja, conxteualizar o request para uso em várias funções que não fazem parte do escopo do request. Exemplo:

// context.ts
import { createContext } from 'fn-context';

export const reqContext = createContext({ req: null, res: null });
// controller.ts
import { reqContext } from './context';

export const getUser = async () => {
  const {req} = reqContext.get();
  
  if(!req.body.user){
    req.body.user = "admin";
    req.body.id = reqContext.id;
  }
  
  return req.body.user;
};

export const controller = async () => {
  const {req} = reqContext.get();
  
  if(!req.body){
    req.body = {};
  }
  
  await getUser();
  
  return req.body;
};
// index.ts
import express from 'express';
import { reqContext } from './context';
import { controller } from './controller';

const app = express();

app.get('/', reqContext.provider(async (req, res) => {
  reqContext.set({req, res});
  res.json(await controller());
}));

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Instalação

npm install fn-context

ou

yarn add fn-context

API

createContext

/**
 * @template T - O tipo do valor padrão do contexto.
 * @template C - O tipo cache do contexto, que deve ser um objeto. Por padrão, é um objeto genérico com chaves do tipo string e valores de qualquer tipo. Útil apenas em casos específicos onde você deseja armazenar valores em cache no contexto.
 * @param defaultValue - O valor padrão do contexto.
 * @returns Um novo contexto de execução.
 */
createContext<T, C extends Object = { [key: string]: any;}>(defaultValue?: T): Context<T>;

Propriedade responsável por criar um novo contexto de execução.

import { createContext } from 'fn-context';

const context = createContext();

Options

  • individual: Se definido como true, o contexto será individual para cada processo iniciado. Ou seja, se você chamar a função fn duas vezes, uma dentro da outra, mas com o mesmo contexto, o conteúdo do contexto será diferente para as duas chamadas. Isso é útil uma situação que precise de um contexto diferente do antecessor. Se como false, será considerado o conteúdo do contexto do antecessor. Útil em situações em que precisa de um contexto global para todas as funções chamadas. Por padrão, é false.
import { createContext } from 'fn-context';

const context = createContext({ foo: 'bar' }, { individual: true });

context.provider

/**
 * @template A - O tipo dos argumentos da função.
 * @template R - O tipo de retorno da função.
 * @param target - A função que será executada.
 * @param defaultValue - O valor padrão do contexto para a função `target`. Se não for definido, o valor padrão do contexto será o valor definido no `createContext`.
 * @returns Uma função que executa a função `target` com o contexto definido.
 */
provider<A extends any[], R = any | void>(target: (...args: A) => Promise<R> | R, defaultValue: T) => (...args: A) => Promise<R>;

Propriedade responsável por fornecer um contexto de execução para uma função.

import { createContext } from 'fn-context';

const context = createContext();

const fn = async () => {
  console.log(context.get());
};

await context.provider(fn, { foo: 'bar' })();

context.get

/**
 * @template T - O tipo do valor do contexto.
 * @returns O valor do contexto.
 */
get(): T;

Propriedade responsável por obter o valor do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.get());

context.set

/**
 * @template T - O tipo do valor do contexto.
 * @param value - O valor do contexto.
 */
set(value: T): void;

Propriedade responsável por definir o valor do contexto.

import { createContext } from 'fn-context';

const context = createContext();

context.set({ foo: 'bar' });

context.id

/**
 * @returns O ID do contexto.
 */
id: string;

Propriedade responsável por obter o ID do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.id);

context.value

/**
 * @template T - O tipo do valor do contexto.
 * @returns O valor do contexto.
 */
value: T;

Propriedade responsável por obter e definir o valor do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.value); // undefined
context.value = { foo: 'bar' };
console.log(context.value); // { foo: 'bar' }

context.cache

/**
 * @template C - O tipo cache do contexto, que deve ser um objeto. Por padrão, é um objeto genérico com chaves do tipo string e valores de qualquer tipo. Útil apenas em casos específicos onde você deseja armazenar valores em cache no contexto.
 * @returns O cache do contexto.
 */
cache: C;

Propriedade responsável por obter e definir valores no cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.cache.has("foo")); // false

context.cache.has

/**
 * @param key - A chave do cache.
 * @returns Se a chave existe no cache.
 */
cache.has(key: string): boolean;

Propriedade responsável por verificar se uma chave existe no cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.cache.has("foo")); // false

context.cache.get

/**
 * @param key - A chave do cache.
 * @returns O valor da chave no cache.
 */
cache.get(key: string): any;

Propriedade responsável por obter um valor do cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

console.log(context.cache.get("foo")); // undefined

context.cache.set

/**
 * @param key - A chave do cache.
 * @param value - O valor da chave no cache.
 */
cache.set(key: string, value: any): void;

Propriedade responsável por definir um valor no cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

context.cache.set("foo", "bar");
console.log(context.cache.get("foo")); // bar

context.cache.delete

/**
 * @param key - A chave do cache.
 */
cache.delete(key: string): void;

Propriedade responsável por deletar um valor do cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

context.cache.set("foo", "bar");
console.log(context.cache.get("foo")); // bar
context.cache.delete("foo");
console.log(context.cache.get("foo")); // undefined

context.cache.clear

/**
 * Limpa o cache do contexto.
 */
cache.clear(): void;

Propriedade responsável por limpar o cache do contexto.

import { createContext } from 'fn-context';

const context = createContext();

context.cache.set("foo", "bar");
console.log(context.cache.get("foo")); // bar
context.cache.clear();
console.log(context.cache.get("foo")); // undefined