<andres-carmona />

TIL #11: Symbol.asyncIterator
First published on
on html, javascript

Symbol.asyncIterator

I am re-reading some parts of the JavaScript reference on MDN and came across several JavaScript features that were unknown to me and are very interesting.

In this case, an object with a Symbol.asyncIterator property that is also a generator, and can produce (yield) values that are then consumed in a for await loop. Simply awesome!

const delayedResponses = {
  delays: [500, 1300, 3500],

  wait(delay) {
    return new Promise((resolve) => {
      setTimeout(resolve, delay);
    });
  },

  async *[Symbol.asyncIterator]() {
    for (const delay of this.delays) {
      await this.wait(delay);
      yield `Delayed response for ${delay} milliseconds`;
    }
  },
};

(async () => {
  for await (const response of delayedResponses) {
    console.log(response);
  }
})();

// Expected output: "Delayed response for 500 milliseconds"
// Expected output: "Delayed response for 1300 milliseconds"
// Expected output: "Delayed response for 3500 milliseconds"

TIL #10: Javascript in 2026
First published on
on html, javascript

I was reading this excellent article on Frontend Masters, where some of the new features already available in JavaScript are described, along with others expected later this year. Among them, the ones I want to highlight most are the following:

Iterator.from:

const result = Iterator.from(array)
  .map(x => x * 2)
  .filter(x => x > 10)
  .take(3)
  .toArray(); // No new arrays created, computation stops after 3

Set methods:

const youKnow  = new Set(["JS", "Python", "CSS", "SQL"]);
const jobNeeds  = new Set(["JS", "TypeScript", "Python"]);

// Skills the job wants that you already have
youKnow.intersection(jobNeeds); // -> Set {"JS", "Python"}

// Everything combined - your full stack + job needs
youKnow.union(jobNeeds); // -> Set {"JS", "Python", "CSS", "SQL", "TypeScript"}

// What the job needs that you DON'T know yet (skill gaps)
jobNeeds.difference(youKnow); // -> Set {"TypeScript"}

// Skills you have that the job doesn't care about
youKnow.difference(jobNeeds); // -> Set {"CSS", "SQL"}

// Skills that appear in only one set, not both
youKnow.symmetricDifference(jobNeeds); // -> Set {"CSS", "SQL", "TypeScript"}

// Are all job requirements a subset of what you know?
jobNeeds.isSubsetOf(youKnow); // -> false

// Do you have every skill and more?
youKnow.isSupersetOf(jobNeeds); // -> false

// Do you and the job have zero overlap?
youKnow.isDisjointFrom(jobNeeds); // -> false

Promise.try:

Promise.try(() => loadUser(id))
  .then(user  => render(user))
  .catch(err  => showError(err));

Import attributes: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import/with

import data from "./file.json" with { type: 'json' }

import exampleStyles from "https://example.com/example_styles.css" with { type: "css" };

document.adoptedStyleSheets.push(exampleStyles);

using and await using: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using

class FileHandle {
  constructor(path) {
    this.path = path;
    console.log(`Opened ${path}`);
  }

  async write(data) {
    // ... write data
  }

  async [Symbol.asyncDispose]() {
    await someFlushOperation();
    console.log(`Flushed and closed ${this.path}`);
  }
}

async function saveData() {
  await using file = new FileHandle("output.txt");
  await file.write("hello world");
  // file is automatically flushed + closed here, even if an error is thrown
}

Array.fromAsync: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync

function createAsyncIter() {
  let i = 0;
  return {
    [Symbol.asyncIterator]() {
      return {
        async next() {
          if (i > 2) return { done: true };
          i++;
          return { value: Promise.resolve(i), done: false };
        },
      };
    },
  };
}

Array.fromAsync(createAsyncIter()).then((array) => console.log(array));

Intl.Collator:

const words = ['äpfel', 'Zebra', 'Bär', 'Apfel', 'über'];
const collator = new Intl.Collator('de');

const sorted = words.sort(collator.compare);
console.log(sorted); // ['Apfel', 'äpfel', 'Bär', 'über', 'Zebra']

TIL #9: ownerDocument.defaultView
First published on
on html, javascript, typescript

Despite considering my self a seasoned programmer and being developing web applications for over 15 years, I’m surprised I didn’t know about the ownerDocument.defaultView property.

I basically returns the window object (or null) associated with a specific DOM node. It could be used to safely attach an event listener to a window object from a component that is rendered outside the main window where the application was initially rendered (think portals).

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");
  const ref = useRef(null);

  useEffect(() => {
    const win = ref.current?.ownerDocument.defaultView || window;

    const toggle = (e) => {
      if (e.metaKey && e.key === "d") {
        e.preventDefault();
        setTheme((t) => (t === "dark" ? "light" : "dark"));
      }
    };

    win.addEventListener("keydown", toggle);

    return () => win.removeEventListener("keydown", toggle);
  }, []);

  return (
    <div ref={ref} className={theme}>
      {children}
    </div>
  );
}

From the same article, also learned about useId and cache 😛

Reference: https://shud.in/thoughts/build-bulletproof-react-components, great article btw! 💯


TIL #8: The Fresnel Effect
First published on
on threejs, glsl, webgl, effects

I’m watching some of the missing lessons on shaders that I have in the Three.js journey course, and today I learned about the Fresnel effect in Three.js. It is used to create a more realistic rendering of materials by simulating how light interacts with surfaces at different angles.

The Fresnel effect causes surfaces to reflect more light at glancing angles, which can enhance the realism of materials like water, glass, and metals.

It can be used for effects like:

  • Glass/Water: Simulating realistic reflections on transparent surfaces.
  • Ghostly/Energy Effects: Creating an inner or outer glow around objects that emphasizes their silhouette.
  • Highlighting Objects: Serving as a low-cost alternative to outline effects for interactive items

Here is a simplified implementation from the Three.js journey course, to create an holographic effect:

// Vertex shader.
varying vec3 vPosition;
varying vec3 vNormal;

void main() {
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);
  vec4 modelNormal = modelMatrix * vec4(normal, 0.0);

  gl_Position = projectionMatrix * viewMatrix * modelPosition;

  vPosition = modelPosition.xyz;
  vNormal = modelNormal.xyz;
}
// Fragment shader.
varying vec3 vPosition;
varying vec3 vNormal;

void main() {
  vec3 normal = normalize(vNormal);

  if(!gl_FrontFacing) {
    normal = -normal;
  }

  // Fresnel effect
  vec3 viewDirection = normalize(vPosition - cameraPosition);
  float fresnel = dot(viewDirection, normal) + 1.0;
  fresnel = pow(fresnel, 2.0);

  // Final output
  gl_FragColor = vec4(vec3(0.0, 1.0, 1.0), fresnel);
}

TIL #7: SVG Filters
First published on
on css, html, svg, effects, filters

SVG filters allow you to create complex visual effects directly within your SVG graphics using a variety of filter primitives. You can apply effects like blurring, color manipulation, and even custom distortions to your SVG elements.

SVG Filters

<p class="ripple-text">SVG Filters</p>

<svg style="position: absolute; width: 0px; height: 0px; pointer-events: none;">
  <filter id="water-ripple">
    <feTurbulence
      type="fractalNoise"
      baseFrequency="0.05"
      numOctaves="2"
      result="ripple"
    >
      <animate
        attributeName="baseFrequency"
        dur="10s"
        values="0.02;0.05;0.02"
        repeatCount="indefinite"
      ></animate>
    </feTurbulence>
    <feDisplacementMap
      in="SourceGraphic"
      in2="ripple"
      scale="5"
    ></feDisplacementMap>
  </filter>
</svg>
.ripple-text {
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: bold;
  text-align: center;
  filter: url(#water-ripple);
}

TIL #6: SVG Favicons
First published on
on css, html, svg, icons
<svg xmlns="http://w3.org/2000/svg" viewBox="0 0 100 100">
  <text y=".9em" font-size="90">👾</text>
</svg>

Reference:

More description SVG favicons and favicons maintain general:


TIL #5: :source % command in vim
First published on
on cli, command, vim, nvim

The command :source % in Vim reloads the Vim configuration file (such as ~/.vimrc) into the current session, updating any changes you’ve made to it. The :source command executes the VimScript commands contained in a file, and % is a shortcut that represents the name of the file currently open in the buffer.

:source %

TIL #4: CSS content-visibility to improve performance
First published on
on css, html, performance

content-visiblity Without Jittery Scrollbars

/* Defer rendering for the 2nd+ article */
body > main > *+* {
  content-visibility: auto;
}
<script type="module">
  let observer = new IntersectionObserver(
    (entries, o) => {
      entries.forEach((entry) => {
        let el = entry.target;
        // Not currently in intersection area.
        if (entry.intersectionRatio == 0) {
          return;
        }
        // Trigger rendering for elements within
        // scroll area that haven't already been
        // marked.
        if (!el.markedVisible) {
          el.attributeStyleMap.set(
            "content-visibility",
            "visible"
          );
          el.markedVisible = true;
        }
      });
    },
    // Set a rendering "skirt" 50px above
    // and 100px below the main scroll area.
    { rootMargin: "50px 0px 100px 0px" }
  );

  let els =
    document.querySelectorAll("body > main > *+*");
  els.forEach((el) => { observer.observe(el); });
</script>

TIL #3: View transitions minimum setup
First published on
on html, css, view transitions

The bare minimum setup for enabling your site to use native view transitions in HTML and CSS:

<meta name="view-transition" content="same-origin" />
@view-transition {
  navigation: auto;
}

Ref URL: https://www.amitmerchant.com/bare-minimum-view-transitions/


TIL #2: Animate details element
First published on
on css, html, css-animations

https://developer.chrome.com/docs/css-ui/animate-to-height-auto#animate_the_details_element

@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }
    
    details {
        transition: height 0.5s ease;
        height: 2.5rem;
        
        &[open] {
            height: auto;
            overflow: clip; /* Clip off contents while animating */
        }
    }
}