angular 提供一种清理计算结果的方法,

yr9zkbsy  于 4个月前  发布在  Angular
关注(0)|答案(4)|浏览(47)

与特性请求相关的@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或带有 allowSignalWriteseffect 管道传递
  • Angular文档应引导用户使用保存前一个值的闭包(或到那个hack的一个 Package 版本,例如ngxtension的 extendedComputedcomputedPrevious )

另请参阅:

ggazkfy8

ggazkfy81#

我的第一个想法是,在这种情况下,拥有onCleanup(类似于我们已经得到的效果)是有意义的。计算显然是一个纯函数,但当重新执行计算时,它确实需要清理。

5sxhfpxr

5sxhfpxr2#

在团队中进一步讨论这个问题 - 从用户的Angular 来看,这个请求是有道理的,但正确实现起来有些困难。更具体地说 - 我们应该在每次重新运行时运行清理函数,以及在计算属性的"destroy"时刻。但是,由于我们没有为计算属性定义任何特定的销毁/终结化逻辑(这由GC处理),因此定义计算属性的"destroy"时刻具有挑战性。

zbdgwd5y

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 type computedResource that must be created in an injection context (like effect ). Then, the cleanup function could be attached to the DestroyRef .
If the signal is read after it is "destroyed" then we could (and maybe this could be user configurable?):

  • keep returning the same value (most JS APIs are designed to be resilient against use-after-"free" anyways, but this is really just kicking the can down the road)
  • return a user-provided sentinel
  • throw an exception (it's probably a bug for a signal to be read outside its lifetime anyways)

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?

yzxexxkh

yzxexxkh4#

对于类似这种情况,一个OwnedComputed确实有一定的意义。值得思考 :)

相关问题