首页 > 解决方案 > 函数使用对象来启动和销毁资源。如何将其重写为提供资源的 HOF?

问题描述

这是我要开始的。convert使用 svgInjector 启动和销毁资源。

export async function convert(
  serializedSvg: string,
  svgSourceId: string,
  containerId: string
): Promise<string> {
  const svgInjector = new SvgInjector(serializedSvg, containerId).inject();
  if (!svgInjector.injectedElement) {
    throw new Error("Svg not injected");
  }

  const doc = new TargetDocument({});
  const xml = convertRecursively(
    svgInjector.injectedElement,
    doc,
    {
      svgSourceId,
    }
  );

  svgInjector.remove();

  return doc.saveXML();
}

我怎样才能重写它,而不是让一个更高阶的函数启动、提供和销毁svgInjector.injectedElement转换函数的资源?

编辑:

这是一个最小的可重现示例:

var svg = '<svg xmlns="http://www.w3.org/2000/svg"><text x="20" y="20">I am made available in DOM</text></svg>'

function convert(
  serializedSvg,
  containerId
) {
  // make resource available (cross-cutting convern)
  var container = document.getElementById(containerId);
  var resource = new DOMParser().parseFromString(serializedSvg, "image/svg+xml").documentElement;
  container.appendChild(resource);

  // core convert functionality does things with resource
  console.log(resource.getBBox())
  
  // clean up resource (cross-cutting concern)
  resource.remove()
}

convert(svg, "container")
<!DOCTYPE html>
<html>
<head>
  <title>Minimal</title>
</head>
<body>
<div id="container">
</div>
</body>
</html>

编辑 2

这是上一次编辑中 JavaScript 的 TypeScript 版本

var svg = '<svg xmlns="http://www.w3.org/2000/svg"><text x="20" y="20">I am made available in DOM</text></svg>'

function convert(
  serializedSvg: string,
  containerId: string
) {
  // make resource available (cross-cutting convern)
  var container = document.getElementById(containerId);
  if (!(container instanceof HTMLDivElement)) {
    throw new Error("Extpected a div element")
  }
  var resource = new DOMParser().parseFromString(serializedSvg, "image/svg+xml").documentElement;
  if (!(resource instanceof SVGSVGElement)) {
    throw new Error("Extpected a svg element")
  }
  container.appendChild(resource);

  // core convert functionality does things with resource
  console.log(resource.getBBox())

  // clean up resource (cross-cutting concern)
  resource.remove()
}

convert(svg, "container")

标签: javascripttypescriptfunctional-programminghigher-order-functions

解决方案


我不确定这是否是您正在寻找的那种东西,但我倾向于反转控制流,以便convert()使用或传递一个“资源管理器”,它负责创建、布置、并删除资源。AResourceManager可能只是一个函数,如:

type ResourceManager<T, I> = <R>(initProps: I, cb: (resource: T) => R) => R;

所以 aResourceManager<T, I>是一个函数,它接受一些类型的初始属性包I来指定T需要哪个类型的资源,以及一个回调函数,在资源可用之后和销毁之前执行实际工作。如果回调函数返回结果,那么资源管理器也会返回结果。

ResourceManager<T, I>是可以重复用于不同类型资源的通用合约。当然,不同类型的资源需要自己的实现。例如,我会像这样退出你的convert()函数ResourceManager<SVGSVGElement, { serializedSvg: string, containerId: string }>

const svgManager: ResourceManager<SVGSVGElement, { serializedSvg: string, containerId: string }> =
  (initProps, cb) => {

    // make resource available)
    var container = document.getElementById(initProps.containerId);
    if (!(container instanceof HTMLDivElement)) {
      throw new Error("Extpected a div element");
    }
    var resource = new DOMParser().parseFromString(initProps.serializedSvg, "image/svg+xml").documentElement;
    if (!(resource instanceof SVGSVGElement)) {
      throw new Error("Extpected a svg element")
    }
    container.appendChild(resource);

    // core functionality
    const ret = cb(resource);

    // clean up resource
    resource.remove()

    // return returned value if we have one
    return ret;
  }

请注意“核心功能”是如何被推迟到回调的,它的返回值被保留以备不时之需。然后convert()简化为:

function convert(
  serializedSvg: string,
  containerId: string
) {
  svgManager({ serializedSvg, containerId }, (resource => console.log(resource.getBBox())));
}

resource => console.log(resource.getBBox())无需关心如何获取或处置resource.


希望对您有所帮助或给您一些想法。祝你好运!

Playground 代码链接


推荐阅读