TypeScript有没有类似Go语言的Defer语句?我厌倦了在整个函数的多个位置编写清理代码。正在寻找一个更简单的解决方案。我做了一个快速谷歌,但没有找到任何东西。
dhxwm5r41#
答案可能是否定的,但您至少有两个选择:1.正如@bereal提到的,你会用try/finally来做这个,关于try/finally,你在评论中说:是的,除了我不想使用try catch块,因为它们可能很昂贵。不完全是这样,抛出一个Error是很昂贵的(昂贵的是创建,填充堆栈信息;实际的“投掷”并不花费太多);输入try代码块就不是了,在JavaScript中,你不必抛出Error示例,你可以抛出任何东西如果你想抛出而不需要填充堆栈信息,你可以抛出一个非Error(尽管我不提倡).另外,finally块有轻微的开销,但我最近不得不在几个现代引擎中测量它,它确实是微不足道的。1.你可以把一个函数赋给一个变量,然后在函数的末尾运行它(或者如果你想做几个的话,可以使用数组),对于单次清理,我预计它会比try/finally更昂贵,对于多次清理(否则需要嵌套的try/finally块),你必须找到答案。FWIW,一些例子:在try/finally中执行单次清理:
try
finally
Error
function example() { try { console.log("hello"); } finally { console.log("world"); } } example();
在try/finally中进行多次清理:
function example() { try { console.log("my"); try { console.log("dog"); } finally { console.log("has"); } } finally { console.log("fleas"); } } example();
通过分配功能进行单一清除:
function example() { let fn = null; fn = () => console.log("world"); console.log("hello"); if (fn) { // Allowing for the above to be conditional, even though // it isn't above fn(); } } example();
function example() { const cleanup = []; cleanup.push(() => console.log("has")); console.log("my"); cleanup.push(() => console.log("fleas")); console.log("dog"); cleanup.forEach(fn => fn()); } example();
或按其他顺序:
function example() { const cleanup = []; cleanup.push(() => console.log("fleas")); console.log("my"); cleanup.push(() => console.log("has")); console.log("dog"); while (cleanup.length) { const fn = cleanup.pop(); fn(); } } example();
e0bqpujr2#
我想要的是一种更清晰的方法来完成defer的工作,就像在TypeScript中执行Go一样:
defer
class Test { @Defer() async test () { const timer = setInterval(() => console.log('interval'), 1000) defer.call(this, () => clearInterval(timer)) await new Promise(resolve => setTimeout(resolve, 1500)) } } const t = new Test() t.test() .catch(console.error)
在上面的代码中,我们定义了一个timer,用于每1秒输出一次interval,并定义了一个defer,用于在超出此函数作用域时清除间隔(与Go相同)。运行时,await new Promise(resolve => setTimeout(resolve, 1500)将等待1.5秒,这将输出一行interval输出,然后程序退出。
timer
interval
await new Promise(resolve => setTimeout(resolve, 1500)
$ ts-node src/defer.ts interval $
下面的代码示例是完整的代码,可以使用TypeScript 4.4通过复制/粘贴直接运行这些代码:
const DEFER_SYMBOL = Symbol('defer') type Callback = (err?: Error) => void interface DeferizedThis { [DEFER_SYMBOL]?: Callback[], } function Defer () { return function callMethodDecorator ( _target : any, _propertyKey : string, descriptor : PropertyDescriptor, ): PropertyDescriptor { const oldValue = descriptor.value async function deferizedMethod ( this: DeferizedThis, ...args: any[] ) { try { const ret = await oldValue.apply(this, args) return ret } finally { if (this[DEFER_SYMBOL]) { const deferCallbacks = this[DEFER_SYMBOL] while (true) { const fn = deferCallbacks?.pop() if (!fn) { break } try { fn() } catch (e) { console.error(e) } } } } } descriptor.value = deferizedMethod return descriptor } } function defer ( this: any, cb: Callback, ): void { if (this[DEFER_SYMBOL]) { this[DEFER_SYMBOL]!.push(cb) } else { this[DEFER_SYMBOL] = [cb] } } class Test { @Defer() async test () { const timer = setInterval(() => console.log('interval'), 1000) defer.call(this, () => clearInterval(timer)) await new Promise(resolve => setTimeout(resolve, 1500)) } } const t = new Test() t.test() .catch(console.error)
如果您已经阅读了上面的代码,它显然是一个有缺陷的PoC,绝对不能在生产中使用。我想讨论一下我们是否有什么好的方法可以在TypeScript中实现这一点,通过遵循这种装饰器的方式,或者其他任何方向。
xkftehaa3#
也许这会有所帮助,从原来的T. J.克劳德(@t-j-克劳德)的React。通过引用try/catch块的finally块中的变量延迟
function example() { const defers = []; try { var xx = "Firts"; defers.push(((text) => () => console.log(text))(xx)); xx = "No Firts"; var yy = "Last"; defers.push(((text) => () => console.log(text))(yy)); yy = "No Last" const timer = setInterval(() => console.log('live'), 1000); defers.push(((t) => () => clearInterval(t))(timer)); } finally { while (defers.length) { const fn = defers.pop(); fn(); } } } example();
3条答案
按热度按时间dhxwm5r41#
答案可能是否定的,但您至少有两个选择:
1.正如@bereal提到的,你会用
try
/finally
来做这个,关于try
/finally
,你在评论中说:是的,除了我不想使用try catch块,因为它们可能很昂贵。
不完全是这样,抛出一个
Error
是很昂贵的(昂贵的是创建,填充堆栈信息;实际的“投掷”并不花费太多);输入try
代码块就不是了,在JavaScript中,你不必抛出Error
示例,你可以抛出任何东西如果你想抛出而不需要填充堆栈信息,你可以抛出一个非Error
(尽管我不提倡).另外,finally
块有轻微的开销,但我最近不得不在几个现代引擎中测量它,它确实是微不足道的。1.你可以把一个函数赋给一个变量,然后在函数的末尾运行它(或者如果你想做几个的话,可以使用数组),对于单次清理,我预计它会比
try
/finally
更昂贵,对于多次清理(否则需要嵌套的try
/finally
块),你必须找到答案。FWIW,一些例子:
在
try
/finally
中执行单次清理:在
try
/finally
中进行多次清理:通过分配功能进行单一清除:
在
try
/finally
中进行多次清理:或按其他顺序:
e0bqpujr2#
我想要的是一种更清晰的方法来完成
defer
的工作,就像在TypeScript中执行Go一样:在上面的代码中,我们定义了一个
timer
,用于每1秒输出一次interval
,并定义了一个defer
,用于在超出此函数作用域时清除间隔(与Go相同)。运行时,
await new Promise(resolve => setTimeout(resolve, 1500)
将等待1.5秒,这将输出一行interval
输出,然后程序退出。下面的代码示例是完整的代码,可以使用TypeScript 4.4通过复制/粘贴直接运行这些代码:
如果您已经阅读了上面的代码,它显然是一个有缺陷的PoC,绝对不能在生产中使用。
我想讨论一下我们是否有什么好的方法可以在TypeScript中实现这一点,通过遵循这种装饰器的方式,或者其他任何方向。
xkftehaa3#
也许这会有所帮助,从原来的T. J.克劳德(@t-j-克劳德)的React。
通过引用try/catch块的finally块中的变量延迟