与特性请求相关的@angular/*包有哪些?
core
描述
假设我有一个状态 imageBlob: Signal<Blob>
,我想使用 URL.createBlobURL
得到一些派生状态 imageBlobUrl: Signal<string>
(也许这样我可以在一个 img
元素中显示它)。天真地,我可以将 imageBlobUrl
定义为:
imageBlobUrl = computed(() => URL.createBlobURL(imageBlob()))
然而,这会泄露对象URL。我应该在哪里调用 URL.revokeObjectURL
?
- (
URL.createBlobURL
/URL.revokeObjectURL
可以替换任何需要显式清理的资源,如打开的WritableStream
、打开的WebSocket、WASM内存中的句柄等。)*
建议的解决方案
computed
可以接受一个额外的选项 cleanup
,该选项在 computed
的值与前一个值发生变化后的某个时间被调用:
imageBlobUrl = computed(() => URL.createBlobURL(imageBlob()), {cleanup: URL.revokeObjectURL})
或者,computed
可以采用类似于 effect
的API来注册清理回调(尽管在这个特定的例子中要麻烦得多):
imageBlobUrl = computed((onCleanup) => {
const ret = URL.createBlobURL(imageBlob());
onCleanup(() => URL.revokeObjectURL(ret));
return ret;
})
请注意,这些API避免将状态性/迟滞引入到 computed
中,并且不指定清理函数何时被调用的具体时间(绕过 #56186 (评论))。
对于 signal
也可以采用类似的API,因为更改完全由用户控制,所以很容易在调用 set
之前立即进行清理。
考虑过的替代方案
- 文档解决方法:
- Angular文档应致力于表明类似情况 需要通过RxJS或带有
allowSignalWrites
的effect
管道传递 - Angular文档应引导用户使用保存前一个值的闭包(或到那个hack的一个 Package 版本,例如ngxtension的
extendedComputed
或computedPrevious
)
4条答案
按热度按时间ggazkfy81#
我的第一个想法是,在这种情况下,拥有
onCleanup
(类似于我们已经得到的效果)是有意义的。计算显然是一个纯函数,但当重新执行计算时,它确实需要清理。5sxhfpxr2#
在团队中进一步讨论这个问题 - 从用户的Angular 来看,这个请求是有道理的,但正确实现起来有些困难。更具体地说 - 我们应该在每次重新运行时运行清理函数,以及在计算属性的"destroy"时刻。但是,由于我们没有为计算属性定义任何特定的销毁/终结化逻辑(这由GC处理),因此定义计算属性的"destroy"时刻具有挑战性。
zbdgwd5y3#
it is challenging to define "destroy" moment for computed as we don't have any specific destroy / finalization logic for computed
(just spitballing)
Perhaps, instead of changing
computed
, we could introduce a new signal typecomputedResource
that must be created in an injection context (likeeffect
). Then, the cleanup function could be attached to theDestroyRef
.If the signal is read after it is "destroyed" then we could (and maybe this could be user configurable?):
I acknowledge that signal-with-a-finite-lifetime is a weird concept to introduce, but maybe it's worth it to support this use-case?
yzxexxkh4#
对于类似这种情况,一个
OwnedComputed
确实有一定的意义。值得思考 :)