Interesting feature of the Go language is to delay the execution of a function until the current function returns - defer keyword.
It allows to declare resource cleanup near the place it created i.e.
file, err := os.Create(fileName)
if err != nil {
return err
}
defer file.Close()
...
file.Close will be called at the end of function
...
The similar feature in js is finally
keyword. The issue with finally
that you open resource in one place but need to close it far far away from opening position.
- easy to make mistake
- in case of dependent resources easy to break order etc.
In js we can have similar behavior like defer using generators, see example:
async function* createResource<T>(open: () => T, close: (a: T) => void) {
let r: T | null = null;
try {
r = open();
yield r;
} finally {
if (r != null) {
close(r);
}
}
}
const open = () => {
console.log('open');
return 'somehandle';
};
const close = (handle: string) => {
console.log(handle, 'closed');
};
for await (let x of createResource(open, close)) {
console.log(1);
await new Promise(x => setTimeout(x, 1000));
console.log(2);
// throw new Error();
}
Output will be: 'open', 1, 2, 'somehandle closed'
Now our resource lifecycle is bounded to "for" block. We declared open
, close
in same place and it's somehow looks like defer
.
PS: createResource
should rethrow Error so its just small simple version to show the idea.
PPS: All above is just for fun to show generators power.
Top comments (0)