我非常喜欢 Python 的上下文管理器,在那里我不必关心资源是如何获得或清理的。有没有办法在 Javascript 中以简洁的方式做到这一点?
The*_*tos 14
您可以使用 javascript 中的生成器函数制作类似的东西:
function* usingGroup() {
// setup
console.group()
try {
yield
} finally {
// cleanup
console.groupEnd()
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,您可以使用for ... of循环:
for(const _ of usingGroup()) {
console.log('inside a group')
}
Run Code Online (Sandbox Code Playgroud)
此方法类似于使用@contextmanager装饰器在 python 中定义上下文管理器的方式。尽管在我看来,使用 for 循环来定义上下文应用位置的方式感觉很奇怪。
它是如何工作的:
抽象掉整个生成器对象和迭代器协议,你可以认为它是这样做的:在循环的第一次迭代之前,生成器函数内部的代码运行直到语句yield,此时,for循环体运行一次生成器已经生成了一个值,在下一次迭代之前,生成器中的其余代码将运行。由于它不会产生,因此循环认为它已完成并退出而不再次执行其主体。这try ... finally确保即使抛出错误,代码也会被执行。
如果您需要在循环中使用某些值(例如您打开的文件),您可以将yield其放在生成器中。
完整代码:
function* usingGroup() {
console.group()
try {
yield
} finally {
console.groupEnd()
}
}
for(const _ of usingGroup()) {
console.log('inside a group')
}
Run Code Online (Sandbox Code Playgroud)
编辑:
由于这个答案似乎引起了一些关注,我认为解决几个问题很重要。
首先,这个技巧可能对大多数人来说是陌生的,并且很可能会导致大多数人感到困惑的代码,我想说这不是一个好的代码风格。为了缓解这种情况,您可以使用基于回调的方法来使正在发生的事情更加明确。
另一个问题是,在其状态下,没有任何东西可以阻止、验证或能够真正验证生成器仅产生一次(如果有的话)。这意味着一些脆弱性,并且您不能真正确定 for 循环体只执行一次。这可以在运行时通过包装/装饰上下文管理生成器函数来修复。
最后,当显式资源管理提案被第四阶段接受时,这个答案将在未来几年变得过时。
我很高兴向您透露这一点,我们现在已经在 JavaScript 中实现了这一点。这是一个名为“contextlib”的小型库(与 python 的 contexlib 非常相似)。
免责声明:我创作了 contextlib。
您可以使用安装npm install contextlib。
import {With, contextmanager} from 'contextlib';
class context:
enter() { console.log('entering context') }
exit() { console.log('leaving context') }
With(new context(), () => {
console.log('inside context')
})
Run Code Online (Sandbox Code Playgroud)
您还可以使用contextmanager装饰器
context = contextmanager(function*(){
try {
console.log('entering context')
yield
} finally {
console.log('leaving context')
}
})
Run Code Online (Sandbox Code Playgroud)
你应该在github上查看一下。
| 归档时间: |
|
| 查看次数: |
361 次 |
| 最近记录: |