使用承诺或回调时装饰器函数返回未定义
Decorator function returning undefined when using promises or callbacks
我正在尝试在节点 js 中创建一个装饰器来记录函数的进入和退出,例如
Executing ServiceClass.sampleService with params 5,1
然后执行完成后 Execution of ServiceClass.sampleService completed with success/error
这适用于 return 数字或字符串或数组或某些对象文字的普通函数,但是当我想装饰一个 return 承诺或回调的函数时,它会记录详细信息,但值未在调用函数的位置 returned。
这是我的示例代码:
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(常规服务class)
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
我在这里错过了什么?
编辑
当我有一个函数 returning 回调函数
时,类似的问题就存在了
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}`);
});
你自己说的,调用函数时不会 returned :-)
您正在 performanceLog
装饰器中执行原始承诺,然后在 then
回调中进行性能测量。这里你传递的是原函数的值,但不要return传到外面。想象一下您的 Promise 调用堆栈是这样的:
sum(51,6)
.then(yourPromiseLog)
.then(theCallbackFromOutside)
解决方案是再次 return 装饰器中的值:
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);
});
希望对您有所帮助!
这是因为您覆盖了 Promise
值。在 then
或 catch
中编辑的值 return 传播到 Promise 链的其余部分。
如果您只想 "spy" 在 Promise
上,则 return
/throw
值或者不 return 一个新的 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
或
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
});
我正在尝试在节点 js 中创建一个装饰器来记录函数的进入和退出,例如
Executing ServiceClass.sampleService with params 5,1
然后执行完成后 Execution of ServiceClass.sampleService completed with success/error
这适用于 return 数字或字符串或数组或某些对象文字的普通函数,但是当我想装饰一个 return 承诺或回调的函数时,它会记录详细信息,但值未在调用函数的位置 returned。
这是我的示例代码:
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(常规服务class)
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
我在这里错过了什么?
编辑
当我有一个函数 returning 回调函数
时,类似的问题就存在了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}`);
});
你自己说的,调用函数时不会 returned :-)
您正在 performanceLog
装饰器中执行原始承诺,然后在 then
回调中进行性能测量。这里你传递的是原函数的值,但不要return传到外面。想象一下您的 Promise 调用堆栈是这样的:
sum(51,6)
.then(yourPromiseLog)
.then(theCallbackFromOutside)
解决方案是再次 return 装饰器中的值:
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);
});
希望对您有所帮助!
这是因为您覆盖了 Promise
值。在 then
或 catch
中编辑的值 return 传播到 Promise 链的其余部分。
如果您只想 "spy" 在 Promise
上,则 return
/throw
值或者不 return 一个新的 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
或
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
});