446 Matching Annotations
  1. Last 7 days
    1. Also referred to as the backend development, Express.js is popularly used to design a web application’s behind-the-scenes architecture. The backend of an application is not visible to the end-users, but it exists. It is an inevitable part of the web application.
    1. To address this issue, and to make it easier for non-web browser environments to implement fetch in a consistent way, WinterCG is working on documenting a subset of the fetch standard that deals specifically with those different requirements and constraints.
  2. May 2022
  3. Apr 2022
    1. Because promise handlers aren’t immediately executed, you might imagine that they act a little like timers — giving the browser a chance to repaint and perform other important tasks before the handler is executed.

      is this because callbacks go into the callback queue ie. lower priority than the microtask queue ?

      promises and mutation observer go into the microtask queue and have higher higher priority, are DOM mutations the "important tasks" that James is refering to ??

    2. In fact, promises aren’t like timers at all. If there are any promise handlers waiting to be executed when your script completes, they’ll be executed immediately.

      is this because promises go into the microtask queue ( higher priority than the callback queue ) ??

    3. rejection handler for then()

      this is also applicable tor .catch() . since catch() is just a special case of .then() ie. .then(null , failure handler). Check the description of promise.catch in the "A Spoonful of Sugar" chapter.

    1. ```js document.createAnnotation()

      document.getAnnotations(nodes)

      document.removeAnnotation(annotation) ```

      ```js Annotation#addTarget(target)

      Annotation#addBody(body) ```

    1. Cache using fetch

      Determine how to cache a resource by setting TTLs, custom cache keys, and cache headers in a fetch request.

      ```js async function handleRequest(request) { const url = new URL(request.url);

      // Only use the path for the cache key, removing query strings // and always store using HTTPS, for example, https://www.example.com/file-uri-here const someCustomKey = https://${url.hostname}${url.pathname};

      let response = await fetch(request, { cf: { // Always cache this fetch regardless of content type // for a max of 5 seconds before revalidating the resource cacheTtl: 5, cacheEverything: true, //Enterprise only feature, see Cache API for other plans cacheKey: someCustomKey, }, }); // Reconstruct the Response object to make its headers mutable. response = new Response(response.body, response);

      // Set cache control headers to cache on browser for 25 minutes response.headers.set('Cache-Control', 'max-age=1500'); return response; }

      addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)); }); ```


      Caching HTML resources

      Setting the cache level to Cache Everything will override the default cacheability of the asset. For time-to-live (TTL), Cloudflare will still rely on headers set by the origin.

      js // Force Cloudflare to cache an asset fetch(event.request, { cf: { cacheEverything: true } });

    1. ``js let originalHTML =

      Hello Mr. Wayne, decide what to do:

      • Call Alfred
      • Take Thalia Al Gul to the cinema
      • Save Gotham
      <span>Use the mouse to choose an option.</span> `;

      let newHTML = `

      Hello Batman, decide what to do:

      • Kill The Joker
      • Save Thalia Al Gul
      • Save Gotham

      <span>Use the batarang to choose an option.</span> `;

      // Diff HTML strings let output = htmldiff(originalHTML, newHTML);

      // Show HTML diff output as HTML (crazy right?)! document.getElementById("output").innerHTML = output; ```

      ```css ins { text-decoration: none; background-color: #d4fcbc; }

      del { text-decoration: line-through; background-color: #fbb6c2; color: #555; } ```

  4. Mar 2022
    1. The URLPattern API provides a web platform primitive for matching URLs based on a convenient pattern syntax.
    1. We can use this functionality as a way to fall back on a default value. If you have a value that might be empty, you can put || after it with a replacement value. If the initial value can be converted to false, you’ll get the replacement instead. The rules for converting strings and numbers to Boolean values state that 0, NaN, and the empty string ("") count as false, while all the other values count as true. So 0 || -1 produces -1, and "" || "!?" yields "!?".
    2. When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it needs, using a set of rules that often aren’t what you want or expect. This is called type coercion. The null in the first expression becomes 0, and the "5" in the second expression becomes 5 (from string to number). Yet in the third expression, + tries string concatenation before numeric addition, so the 1 is converted to "1" (from number to string).
    1. ```js

      //If you write your own code, remember hex color shortcuts (eg., #fff, #000)

      function hexToRgbA(hex){ var c; if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){ c= hex.substring(1).split(''); if(c.length== 3){ c= [c[0], c[0], c[1], c[1], c[2], c[2]]; } c= '0x'+c.join(''); return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+',1)'; } throw new Error('Bad Hex'); }

      hexToRgbA('#fbafff')

      / returned value: (String) rgba(251,175,255,1) / ```

  5. Feb 2022
    1. Records and Tuples break that convention, and allow us to compare by value. Deep comparisons of objects has been something that's been quite tricky in Javascript for a long time, but with Tuples and Records we can finally do that. As such, the following code returns true:

      js console.log(#{ a: { b : 3 }} === #{ a: { b : 3 }}) // return true console.log(#[1, 2, 3] === #[1, 2, 3]) // returns true

    1. Integrating AbortController

      js export const Timeout = (time) => { let controller = new AbortController(); setTimeout(() => controller.abort(), time * 1000); return controller; }

      ```js import { useEffect, useState } from "react"; //imports goes here

      export default function App() { //state goes here

      //update useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/1", { signal: Timeout(10).signal }) .then((resp) => resp.json()) .then((resp) => setData(resp)) .catch((err) => setError(true)); return () => {}; }, []); return ( <div> {* JSX goes here*} </div> ); } ```

    1. 2. Timeout a fetch() request

      ```js async function fetchWithTimeout(resource, options = {}) { const { timeout = 8000 } = options;

      const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); const response = await fetch(resource, { ...options, signal: controller.signal<br /> }); clearTimeout(id); return response; }

      async function loadGames() { try { const response = await fetchWithTimeout('/games', { timeout: 6000 }); const games = await response.json(); return games; } catch (error) { // Timeouts if the request takes // longer than 6 seconds console.log(error.name === 'AbortError'); } } ```

    1. since then I hate the Node JS ecosystem

      So Gitea—or Codeberg, at least—should be amenable to the suggestion of un-messing the process of self-hosting where it brings the aspiring self-hoster into contact with NodeJS/NPM silliness. Make that part optional.

    1. Reacquiring a wake lock

      The following code reacquires the wake lock should the visibility of the document change and the wake lock is released.

      js document.addEventListener('visibilitychange', async () => { if (wakeLock !== null && document.visibilityState === 'visible') { wakeLock = await navigator.wakeLock.request('screen'); } });

  6. Jan 2022
    1. A note on setting worker-loader’s publicPath with webpack 5

      Webpack 5 introduced a mechanism to detect the publicPath that should be used automatically

      [...]

      Webpack 5 exposes a global variable called __webpack_public_path__ that allows you to do that.

      // Updates the `publicPath` at runtime, overriding whatever was set in the
      // webpack's `output` section.
      __webpack_public_path__ = "/workers/";
      
      const myWorker = new Worker(
        new URL("/workers/worker.js");
      );
      
      // Eventually, restore the `publicPath` to whatever was set in output.
      __webpack_public_path__ = "https://my-static-cdn/";
      
    1. Mermaid lets you create diagrams and visualizations using text and code.It is a Javascript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
    1. function parseLinkHeader( linkHeader ) {
         const linkHeadersArray = linkHeader.split( ", " ).map( header => header.split( "; " ) );
         const linkHeadersMap = linkHeadersArray.map( header => {
            const thisHeaderRel = header[1].replace( /"/g, "" ).replace( "rel=", "" );
            const thisHeaderUrl = header[0].slice( 1, -1 );
            return [ thisHeaderRel, thisHeaderUrl ]
         } );
         return Object.fromEntries( linkHeadersMap );
      }
      
  7. Dec 2021
    1. Web Workers

      As of webpack 5, you can use Web Workers without worker-loader.

      Syntax

      new Worker(new URL('./worker.js', import.meta.url));
      
    1. Instant Dates and Times

      Temporal.Instant returns an object representing a date and time to the nearest nanosecond according to an ISO 8601 formatted string:

    1. // main.js
      const { RemoteReadableStream, RemoteWritableStream } = RemoteWebStreams;
      (async () => {
        const worker = new Worker('./worker.js');
        // create a stream to send the input to the worker
        const { writable, readablePort } = new RemoteWritableStream();
        // create a stream to receive the output from the worker
        const { readable, writablePort } = new RemoteReadableStream();
        // transfer the other ends to the worker
        worker.postMessage({ readablePort, writablePort }, [readablePort, writablePort]);
      
        const response = await fetch('./some-data.txt');
        await response.body
          // send the downloaded data to the worker
          // and receive the results back
          .pipeThrough({ readable, writable })
          // show the results as they come in
          .pipeTo(new WritableStream({
            write(chunk) {
              const results = document.getElementById('results');
              results.appendChild(document.createTextNode(chunk)); // tadaa!
            }
          }));
      })();
      
      // worker.js
      const { fromReadablePort, fromWritablePort } = RemoteWebStreams;
      self.onmessage = async (event) => {
        // create the input and output streams from the transferred ports
        const { readablePort, writablePort } = event.data;
        const readable = fromReadablePort(readablePort);
        const writable = fromWritablePort(writablePort);
      
        // process data
        await readable
          .pipeThrough(new TransformStream({
            transform(chunk, controller) {
              controller.enqueue(process(chunk)); // do the actual work
            }
          }))
          .pipeTo(writable); // send the results back to main thread
      };
      
    1. 
      //getDates.js
      
      // Returns an array of dates between the two dates
      function getDates (startDate, endDate) {
        const dates = []
        let currentDate = startDate
        const addDays = function (days) {
          const date = new Date(this.valueOf())
          date.setDate(date.getDate() + days)
          return date
        }
        while (currentDate <= endDate) {
          dates.push(currentDate)
          currentDate = addDays.call(currentDate, 1)
        }
        return dates
      }
      
      // Usage
      const dates = getDates(new Date(2013, 10, 22), new Date(2013, 11, 25))
      dates.forEach(function (date) {
        console.log(date)
      })
      
    1. /**
       * Fetch and process the stream
       */
      async function process() {
        // Retrieve NDJSON from the server
        const response = await fetch('http://localhost:3000/request');
      
        const results = response.body
          // From bytes to text:
          .pipeThrough(new TextDecoderStream())
          // Buffer until newlines:
          .pipeThrough(splitStream('\n'))
          // Parse chunks as JSON:
          .pipeThrough(parseJSON());
      
        // Loop through the results and write to the DOM
        writeToDOM(results.getReader());
      }
      
      /**
       * Read through the results and write to the DOM
       * @param {object} reader 
       */
      function writeToDOM(reader) {
        reader.read().then(({ value, done }) => {
          if (done) {
            console.log("The stream was already closed!");
      
          } else {
            // Build up the values
            let result = document.createElement('div');
            result.innerHTML =
              `<div>ID: ${value.id} - Phone: ${value.phone} - Result: $
                  {value.result}</div><br>`;
      
            // Prepend to the target
            targetDiv.insertBefore(result, targetDiv.firstChild);
      
            // Recursively call
            writeToDOM(reader);
          }
        }, e => console.error("The stream became errored and cannot be read from!", e) ); }
      
    1. function getDomPath(el) {
        var stack = [];
        while ( el.parentNode != null ) {
          console.log(el.nodeName);
          var sibCount = 0;
          var sibIndex = 0;
          for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
            var sib = el.parentNode.childNodes[i];
            if ( sib.nodeName == el.nodeName ) {
              if ( sib === el ) {
                sibIndex = sibCount;
              }
              sibCount++;
            }
          }
          if ( el.hasAttribute('id') && el.id != '' ) {
            stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
          } else if ( sibCount > 1 ) {
            stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
          } else {
            stack.unshift(el.nodeName.toLowerCase());
          }
          el = el.parentNode;
        }
        return stack.slice(1); // removes the html element
      }
      
      //Usage:
      var path = getDomPath(document.getElementById('button'));
      console.log(path.join(' > '));
      
    1. Using Web Workers

      You can run highlighting inside a web worker to avoid freezing the browser window while dealing with very big chunks of code.

      // In your main script:
      addEventListener('load', () => {
        const code = document.querySelector('#code');
        const worker = new Worker('worker.js');
        worker.onmessage = ({data}) => { code.innerHTML = data; }
        worker.postMessage(code.textContent);
      });
      
      // In worker.js:
      
      onmessage = (event) => {
        importScripts('<path>/highlight.min.js');
        const result = self.hljs.highlightAuto(event.data);
        postMessage(result.value);
      };
      
    1. API

      In order to access the JavaScript object which provides the SoundCloud Widget API, add this script to your html page.

      This script exposes the SC.Widget(/*iframeElement|iframeElementID*/) function to the global scope. It allows you to control the widget from the parent page (the page the widget is inserted into). SC.Widget accepts the reference to the iframe element or its id.

      var iframeElement   = document.querySelector('iframe');
      var iframeElementID = iframeElement.id;
      var widget1         = SC.Widget(iframeElement);
      var widget2         = SC.Widget(iframeElementID);
      // widget1 === widget2