Обзор приложения ES7 Decorator

Node.js внешний интерфейс JavaScript TypeScript

Многие объектно-ориентированные языки имеютДекораторФункции, изменяющие поведение класса. В настоящее время этот метод внедренES7, но ни популярные браузеры, ни Node.js не особенно дружелюбны к нему.

Итак, для использования в проектеDecoratorЕсли вам нужно использоватьBabelПереведите или используйте расширенный набор JavascriptTypescriptразвивать.

Если вы мало знаете о деталях этой грамматики, вы можете продвинуть этот портал: http://es6.ruanyifeng.com/#docs/decorator, и узнать о его особенностях у господина Жуана Ифэна.

первоначальное намерение

использоватьдекораторПервоначальное намерение состоит в том, чтобы сделать что-то лучше, не изменяя исходный интерфейс. подобно:

  • Мобильный телефон можно использовать, но его можно предотвратить, добавив чехол для мобильного телефона;
  • В кресле можно сидеть, но удобнее сидеть на подушке;
  • Винтовка может стрелять, но она может стрелять точнее с добавлением оптического прицела;
  • ......

Если вы хотите понять это более абстрактно, в области компьютеров его можно применять для сбора журналов, перехвата ошибок, проверки безопасности, кэширования, отладки, сохранения и т. д.

Обычно используемые декораторы

Обычно используемые декораторы обычнодекоратор классаа такжедекоратор метода, конечно будетдекоратор недвижимости, но обсуждать особо нечего.

декоратор класса

В основном используется для конструкторов классов, аргументы которых являются конструктором класса:

function testable(target) {
    target.prototype.isTestable = true
}

@testable
class MyTestableClass {}

let obj = new MyTestableClass()
obj.isTestable // true

Уведомление:здесьtargetЕсли вы добавите метод непосредственно к параметру, вы получите статический метод, который эквивалентенclassдобавить перед методомstaticключевое слово; если вы хотите добавить атрибуты экземпляра, вы можете передать целевому классуprototypeманипулирование объектами.

Теперь мы используемдекоратор классаРеализуйте декоратор, который фиксирует время выполнения метода:

const sleepTimeClass = (timeHandler?: (time?: number) => void) => (target: any) => {
    Object.getOwnPropertyNames(target.prototype).forEach(key => {
        const func = target.prototype[key]
        target.prototype[key] = async (...args: any[]) => {
            const startTime = await +new Date()
            await func.apply(this, args)
            const endTime = await +new Date()
            timeHandler && await timeHandler(endTime - startTime)
        }
    })
    return target
}

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

const sleepTimeClassTimer = sleepTimeClass(time => {
    console.log('执行时间', `${time}ms`)
})

@sleepTimeClassTimer
class homepageController {
    async get(ctx: any) {
        ctx.response.body = await pageService.homeHtml('/page/helloworld', '/page/404')
    }
}

Таким образом каждый разclassПосле выполнения метода in будет распечатано соответствующее время выполнения.

декоратор метода

function readonly(target, name, descriptor){
    // descriptor对象原来的值如下
    // {
    //   value: specifiedFunction,
    //   enumerable: false,
    //   configurable: true,
    //   writable: true
    // }
    descriptor.writable = false
    return descriptor
}

readonly(Person.prototype, 'name', descriptor)
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor)

Поскольку в асинхронном программированииasyncа такжеawaitИсключение трудно поймать, если принудительноtry...catchСделаем, улов бесконечный, код все равно выглядит некрасиво, использовать декоратор очень просто:

const asyncMethod = (errorHandler?: (error?: Error) => void) => (...args: any[]) => {
    const func = args[2].value
    return {
        get() {
            return (...args: any[]) => {
                return Promise.resolve(func.apply(this, args)).catch(error => {
                    errorHandler && errorHandler(error)
                })
            }
        },
        set(newValue: any) {
            return newValue
        }
    }
}

Затем используйте декоратор метода:

const errorAsyncMethod = asyncMethod(error => {
    console.error('错误警告', error)
})

class homepageController {
    @errorAsyncMethod async get(ctx: any) {
        ctx.response.body = await pageService.homeHtml('/page/helloworld', '/page/404')
    }
}

Порядок загрузки декоратора

У класса или метода может быть много вложенных декораторов, поэтому также важно знать порядок их выполнения:

  • При наличии нескольких декораторов параметров они выполняются последовательно, начиная с последнего параметра;
  • Сначала выполняется декоратор параметров в методе и параметрах метода;
  • Декораторы класса всегда выполняются последними;
  • Декораторы методов и свойств, кто придет первым, тот и выполнится первым;
  • Поскольку параметр является частью метода, он всегда будет выполняться рядом с методом.

Применение декораторов

Это уже было упомянуто в первоначальном замысле.Попробуйте представить, что ему нужно всего несколько декораторов, чтобы завершить базовую производительность и лог-мониторинг фронтенда и бэкенда.Разве это не интересно?