Стекируемые функции - PullRequest
       42

Стекируемые функции

1 голос
/ 29 октября 2019

Я ищу не зависящий от библиотеки способ «сложить» функции. Парадигма, к которой я привык, - это «промежуточное программное обеспечение», где что-то происходит в функции, могут возникать ошибки, и глобальный context (или req) используется для присоединения новых свойств или изменения существующих. Эти идеи можно найти в таких библиотеках, как express или type-graphql.

. Я ищу какой-то независимый способ связывания промежуточного программного обеспечения, не зависящий от библиотек этого типа.

Вот пример того, какие функции у меня есть.

Я борюсь с каким-то чистым способом создания функций. Глобальный подход не является обязательным для правильной типизации с использованием машинописи и не очень функционален.

Там, где более функциональному подходу не хватает такого рода «цепочечной гибкости», где я могу просто иметь массив функций, как показано ниже.

// logs the start of middleware
context.utility.log(debug, ids.onLoad),
// fetches user by email submitted
context.potentialUser.fetchByEmail(SignupOnSubmitArgs),
// throws error if the user is found
context.potentialUser.errorContextPropPresent,
// checks if passowrd and reenterPassword match
context.potentialUser.signupPassword(SignupOnSubmitArgs),
// creates the user
context.user.create(SignupOnSubmitArgs, ''),
// thows error if create failed in some way
context.user.errorContextPropAbsent,
// adds user id to session
context.utility.login,
// redirects user to dashboard
context.utility.redirect(Pages2.dashboardManage)

Существуют ли какие-либо инструменты / библиотеки, которые позволят создавать и очищать цепные функции и склеивать их друг с другом в стеке?

1 Ответ

1 голос
/ 29 октября 2019

Возвращение this - это, как правило, способ цепочки методов. Я сделал вам пример, показывающий как синхронизирующие, так и асинхронные функции:

class ChainedOperations {
  constructor(private value: number){}

  public add(n: number): this {
    this.value += n;
    return this;
  }

  public subtract(n: number): this {
    this.value -= n;
    return this;
  }

  public async send(): Promise<this> {
    console.log(`Sending ${this.value} somewhere`);
    return this;
  }
}

async function somewhereElse(): Promise<void> {
  const firstChain = await new ChainedOperations(1).add(1).subtract(1).send();
  await firstChain.add(1).subtract(2).send()
}

somewhereElse().catch(e => { throw new Error(e) });

Для лучшей работы с асинхронными функциями вы можете использовать паттерн конвейера, где вы соединяете цепи, но также ждете окончательного результата и передаете его следующему парню:

abstract class Pipable {
  public pipe(...functions: Function[]) {
    return (input: any) => functions.reduce((chain, func: any) => chain.then(func.bind(this)), Promise.resolve(input));
  }
}

class AClass extends Pipable {

  constructor(private value: number){
    super();
  }

  public add(n: number): number {
    this.value += n;
    return this.value;
  }

  public subtract(n: number): number {
    this.value -= n;
    return this.value;
  }

  public async send(): Promise<number> {
    console.log(`Sending ${this.value} somewhere`);
    return this.value;
  }
}


async function Something(){
  const myClass = new AClass(2);
  const composition = await myClass.pipe(myClass.add, myClass.subtract, myClass.send)(2);
}

Something();

Некоторым людям не нравится начинать с начала, но они идут назад от последней функции. Если вы хотите, просто замените .reduce на .reduceRight. Если вам нравятся причудливые имена, начиная с последней, называется Композицией, а не трубами.

...