DEV Community

loading...

Exploring How lit-html Works: render Function

nozomuikuta profile image Nozomu Ikuta ・2 min read

In this series, How lit-html works, I will explore (not explain) internal implementation of lit-html.

In the last 4 posts, we saw what TemplateResult and SVGTemplateResult looks like.

From now on, I will explore the render function.

render function

render function is defined beside a variable whose name is parts.

export const parts = new WeakMap<Node, NodePart>();

export const render =
    (result: unknown,
     container: Element|DocumentFragment,
     options?: Partial<RenderOptions>) => {
      let part = parts.get(container);
      if (part === undefined) {
        removeNodes(container, container.firstChild);
        parts.set(
            container,
            part = new NodePart(
                {
                  templateFactory,
                  ...options,
                },
                undefined));
        part.appendInto(container);
      }
      part.setValue(result);
      part.commit();
    };
Enter fullscreen mode Exit fullscreen mode

This function receives two arguments. First one is an instance of TemplateResult or SVGTemplateResult. Second is the container, which is a DOM parent inside which the content is rendered.

Searching Cache

Firstly, render function checks if an instance of NodePart class is stored in parts with the container as a key.

Create a New NodePart

If a cached NodePart instance is not found, then all the direct children of the container are removed by removeNodes function.

export const removeNodes =
    (container: Node, start: Node|null, end: Node|null = null): void => {
      while (start !== end) {
        const n = start!.nextSibling;
        container.removeChild(start!);
        start = n;
      }
    };
Enter fullscreen mode Exit fullscreen mode

The algorithm is quite similar to reparentNodes function that I saw in the last post. Only difference is how the functions manipulate DOM tree.

After cleaning up the container, a new NodePart instance is registered into the parts and is associated with with the container.

Rendering

Finally, render function lets the NodePart instance call three methods of it, but I will explore this part in later posts. Instead, I will recap what WeakMap is, because it's worth using in other development as well.

WeakMap

MDN says that the WeakMap object is a collection of key/value pairs and the keys must be objects.

The word "weak" here means that the reference from weak map to the key object doesn't prevent the object from being garbage collected.

Thus, it is really convenient to store data in a WeakMap as a cache. We don't have to check, every time we do something or periodically the data of the object, whether the data is no longer used.

Just for information, there are also Map, Set, WeakSet, each of which has suitable situation.

Summary

So far, I learned the following points:

  • render function caches NodePart.
  • render function creates a new NodePart if no corresponding cache is found.
  • render function delegates actual rendering process to the NodePart instance.

From the next post, I will dive into the NodePart class.

Discussion (0)

Forem Open with the Forem app