【问题标题】:How to write a middleware for the functions in typescript namespace如何为打字稿命名空间中的函数编写中间件
【发布时间】:2018-01-11 11:26:57
【问题描述】:

我想为 typescript 中的命名空间编写一个中间件。因此,当调用命名空间中的任何函数时,中间件应该触发并检查是否可以执行预期的函数。示例:

namespace Foo.Bar {
  function middleware(next) {
     if (enabled) next();
  }
  export function baz() {
     // Do Something
  }
}

如果我调用 baz Foo.Bar.baz(),我希望我的中间件方法首先触发。 如果是模块,我可以像这样导出函数对象:

export {baz: middleware}

但命名空间不允许这样做。有什么建议吗?

【问题讨论】:

  • 你能在问题中提供一个例子吗
  • namespace Foo.Bar { applyMiddleWare(next) { if (enabled) next(); } export function trigger() { // So Something } } 所以当触发方法被调用时,我想先执行一个中间件函数。而那个中间件将决定是否执行触发功能。
  • 这个问题很快就会被关闭,除非你用更好的解释和一些代码来编辑它。
  • 如果我可以维护 Foo.Bar 和调用函数,我可以将它更新为类。所以我仍然必须调用 Foo.Bar.baz() 因为我的所有应用程序都是使用它构建的,我现在不想更改这个命名约定。

标签: javascript typescript ecmascript-6 namespaces javascript-namespaces


【解决方案1】:

如果您对一些“肮脏的”类似 js 的编码感到满意,那么下一个方法可能会对您有所帮助:

namespace Foo.Bar {
    export function middleware(next) {
        alert("middleware");
        next();
    }
    export function baz() {
        alert("baz");
        // Do Something
    }
}

// Simple call
Foo.Bar.baz();

// "Middleware magic"
const origMethod = Foo.Bar.baz;
Foo.Bar.baz = () => {
    Foo.Bar.middleware(origMethod);
}
// Middleware call
Foo.Bar.baz();

可以在TS playground site上测试。

【讨论】:

  • 这很棒。但我认为这不是我的应用程序的最佳方法。我们可以维护命名空间Foo.Bar 并拥有一个导出函数对象的类吗?
  • 如果每次有人调用 Foo.Bar.baz() 方法时,如果您需要在执行原始代码之前运行您的代码,除了创建新函数而不是原始函数之外别无他法Foo.Bar.baz.
【解决方案2】:

这是一个使用静态类和方法decorators的示例。

foo.ts

// method decorator    
function middleware() {
    return function(target: any, propertyKey: string) {
        // exec middleware
        console.log('middleware')
    }
}

export namespace Foo {

    export class Bar {
        constructor() {
            throw new Error('Instantiating is not allowed');
        }

        @middleware()
        static baz() {
            console.log('after middleware');
        }
    }
}

这仍将是您的命名空间约定。

index.ts

import { Foo } from './foo';

Foo.Bar.baz();

这个中间件会在baz方法被调用之前触发。但是,如果您的中间件是 async 并且您需要装饰方法来等待中间件完成,您可以将中间件更改为如下所示:

function middleware() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        let fn = descriptor.value;

        return {
            configurable: true,
            get() {
                return () => {
                    console.log('middleware');

                    wait(1000).then(() => wait(1000)).then(() => fn.call());
                }
            }
        }
    };
}

function wait(millis: number) {
    console.log(`wait ${millis}ms`);

    return new Promise<void>(resolve => {
        setTimeout(resolve, millis);
    });
}

或者,如果您更喜欢asyncawait,您可以更改get 函数以返回Promise&lt;void&gt; 类型的函数:

get() {
    return async () => {
        console.log('middleware')

        await wait(1000);

        await wait(1000);

        fn.call();
    }
}

【讨论】:

    猜你喜欢
    • 2016-11-05
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 2017-02-09
    • 2017-11-13
    • 1970-01-01
    • 2019-10-13
    • 2020-05-28
    相关资源
    最近更新 更多