使用promises或callback时,Decorator函数返回undefined

时间:2018-03-13 10:11:17

标签: javascript typescript decorator typescript-decorator

我正在尝试在节点js中创建一个装饰器来记录条目并在执行时退出函数,例如 Executing ServiceClass.sampleService with params 5,1 然后在执行结束后Execution of ServiceClass.sampleService completed with success/error

这适用于返回数字或字符串或数组或某些对象文字的普通函数,但是当我想要修饰一个返回promise或callback的函数时,它会记录详细信息,但是在调用函数的地方不会返回值。 / p>

以下是我的示例代码:

logger.ts (包含装饰器功能)

export function performanceLog(target, name, descriptor) {
    const original = descriptor.value;
    if (typeof original === 'function') {
        descriptor.value = function (...args) {
            console.log(`Executing ${target.constructor.name}.${name} with parameters ${args}`);
            // Execute function like a function with promise
            let start: any = new Date();
            return original.apply(this, args).then(data => {
                let end: any = new Date();
                end = end-start;
                console.log(`\nExecution of ${target.constructor.name}.${name} completed successfully in ${end / 1000} seconds`);
            }).catch(error => {
                let end: any = new Date();
                end = end-start;
                console.log(`\nExecution of ${target.constructor.name}.${name} completed with error in ${end / 1000} seconds`);
            });
        }
    }
    return descriptor;
}

sampleService.ts (常规服务类)

import { performanceLog } from '../utilities/logger';

let err = false;
export default class SampleService {
    @performanceLog
    public sum(a, b) {
        return new Promise((resolve, reject) => {
            if (err) {
                reject(a - b);
            } else {
                resolve(a + b);
            }
        })
    }
}

const e = new SampleService();
e.sum(51, 6).then(data => console.log("## Data: ", data)).catch(err => console.log("##err: ", err));
// Here data is undefined and it never goes into the catch part either

我在这里缺少什么?

修改

当我有一个返回回调函数的函数

时,类似的问题就出现了
export default class SampleService {
    @performanceLog
    public sum(a, b, callback) {
        // return new Promise((resolve, reject) => {
        if (err) {
            return callback(a - b, null);
        } else {
            return callback(null, a+b);
        }
        // })
    }
}

const e = new SampleService();
// e.sum(51, 6).then(data => console.log("## Data: ", data)).catch(err => console.log("##err: ", err));

e.sum(51, 6, function (err, res) {
    console.log(`This is err  ${err} and res ${res}`);
});

2 个答案:

答案 0 :(得分:1)

你自己说过,调用函数时不会返回值:-) 您正在performanceLog装饰器中执行原始承诺,然后在then回调中进行性能测量。在这里传递原始函数的值,但不要返回到外部。想象一下你的Promise callstack是这样的:

sum(51,6)
  .then(yourPromiseLog)
  .then(theCallbackFromOutside)

解决方案是再次在装饰器中返回值:

return original.apply(this, args).then(data => {
  let end: any = new Date();
  end = end-start;
  console.log(`\nExecution of ${target.constructor.name}.${name} completed successfully in ${end / 1000} seconds`);
  return data;
})

同样,你必须在catch回调中再次抛出错误:

catch(error => {
  let end: any = new Date();
  end = end-start;
  console.log(`\nExecution of ${target.constructor.name}.${name} completed with error in ${end / 1000} seconds`);
  return Promise.reject(error);
});

希望这有帮助!

答案 1 :(得分:1)

这是因为您覆盖了Promise值。 thencatch中返回的值将传播到Promise链的其余部分。

如果您只是希望“监视”Promise,然后return / throw值,或者不返回新的Promise。示例:

const promise = original.apply(this, args)

promise.then(data => {
    let end: any = new Date();
    end = end-start;
    console.log(`\nExecution of ${target.constructor.name}.${name} completed successfully in ${end / 1000} seconds`);
}).catch(error => {
    let end: any = new Date();
    end = end-start;
    console.log(`\nExecution of ${target.constructor.name}.${name} completed with error in ${end / 1000} seconds`);
});

return promise

OR

return original.apply(this, args).then(data => {
    let end: any = new Date();
    end = end-start;
    console.log(`\nExecution of ${target.constructor.name}.${name} completed successfully in ${end / 1000} seconds`);

    // propagate the return value
    return data;
}).catch(error => {
    let end: any = new Date();
    end = end-start;
    console.log(`\nExecution of ${target.constructor.name}.${name} completed with error in ${end / 1000} seconds`);

    // propagate the error value
    throw error
});