发布于 2020-03-25 19:31:43
可以说答案是否定的,但你至少有几个选择:
try/finally来实现。Re try/finally,你在评论中说:是的,除非我不想使用try catch块,因为它们可能很昂贵。
不怎么有意思。抛出异常的开销很大,而进入try块则不是。finally块有轻微的开销,但我最近不得不在几个现代引擎中测量这一点,这真的是令人惊讶的微不足道。
try/finally更昂贵。对于多个(否则将需要嵌套的try/finally块),那么,您必须找出答案。FWIW,一些例子:
在try/finally中执行一次清理
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();
try/finally中的多重清理
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();
发布于 2021-08-01 06:36:57
我想要的是一种更清晰的方式来完成与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)在上面的代码中,我们定义了一个每隔1秒输出interval的timer,并定义了一个在超出此函数范围时清除interval的defer (与Go相同)。
当运行它时,await new Promise(resolve => setTimeout(resolve, 1500)将等待1.5秒,这将输出一行interval输出,然后程序退出。
$ 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)如果你读过上面的代码,它显然是一个有be的PoC,绝对不能在生产中使用。
我想讨论一下,如果我们在TypeScript中有任何好的方法来实现这一点,通过遵循这个装饰器的方式,或者任何其他方向。
发布于 2021-10-24 23:20:11
也许这会有所帮助,来自原始的T.J. Crowder(@t-j-crowder)回复。
通过引用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();
https://stackoverflow.com/questions/60847836
复制相似问题