powerfulyang's Technical Blog

website·Indexed 32 days ago

https://powerfulyang.com

A collection of technical notes and guides covering frontend development, JavaScript, React 18, TypeScript, and data structures. Topics include browser caching, CORS, XSS/CSRF, Web Workers, RxJS, NestJS, and algorithm implementations like Quicksort and KMP, as well as system administration tips for SSH, Hyper-V, and OpenWrt.

Tokens
111.9K
Snippets
502
Records
769
Agent score
61%

What's inside powerfulyang

  1. Overview of Trie (Prefix Tree) Data Structure

    A Trie (also known as a prefix tree or dictionary tree) is an efficient data structure used for string operations such as insertion, deletion, and searching. Each node represents a character, and the path from the root to a leaf node represents a string.

    Key characteristics:

    • Time Complexity: Search, insert, and delete operations take O(m) time, where m is the length of the string, regardless of the total number of strings stored.
    • Space Complexity: High, as each node typically stores a pointer array for child nodes. This can be optimized using Radix Trees or Ternary Search Trees.
    • Primary Use Cases: Auto-completion, spell checkers, IP routing (longest prefix match), word frequency counting, and dictionary lookups.
  2. Understand the FiberNode structure in React

    In React, every JSX node is converted into a Fiber node. A Fiber node is a JavaScript object that represents a unit of work and contains metadata about the component, its state, and its relationship to other nodes in the tree. Key properties include:

    • tag: The type of the node (e.g., FunctionComponent, ClassComponent).
    • key: A unique identifier used during the diffing process to determine if an item was modified, added, or deleted.
    • type: The element type (e.g., 'div', 'span' for HTML tags, or the function/class for components).
    • stateNode: The actual DOM element (for DOM nodes) or the component instance (for class components). For function components, this is null.
    • pendingProps: The props currently being applied to the node.
    • flags: Indicates the update priority of the node (e.g., NoFlags means no update).
    • subtreeFlags: Indicates if child nodes need updates; if NoFlags, the reconciler can skip the subtree during diffing.
    • alternate: A pointer to the opposite tree (current vs. work-in-progress) used for double-buffering to prevent data loss and improve efficiency.
    function FiberNode(tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode) {
      this.tag = tag;
      this.key = key;
      this.elementType = null;
      this.type = null;
      this.stateNode = null;
      this.return = null;
      this.child = null;
      this.sibling = null;
      this.index = 0;
      this.ref = null;
      this.pendingProps = pendingProps;
      this.memoizedProps = null;
      this.updateQueue = null;
      this.memoizedState = null;
      this.dependencies = null;
      this.mode = mode;
      this.flags = NoFlags;
      this.subtreeFlags = NoFlags;
      this.deletions = null;
      this.lanes = NoLanes;
      this.childLanes = NoLanes;
      this.alternate = null;
    }
  3. Manage memory with Ownership and Borrowing

    Rust ensures memory safety without a garbage collector through a set of ownership rules:

    1. Every value has a variable called its owner.
    2. There can only be one owner at a time.
    3. When the owner goes out of scope, the value is dropped.

    Borrowing allows accessing data via references (&) without taking ownership. Slices are references to a contiguous sequence of elements in a collection, allowing you to reference a part of a string or array without copying the data.

    fn main() {
        let s1 = String::from("hello");
        let s2 = s1.clone(); // Explicit copy of heap data
    
        let s = String::from("hello world");
        let word = first_word(&s); // Borrowing s
        println!("First word is: {}", word);
    }
    
    // Returns a string slice (&str)
    fn first_word(s: &String) -> &str {
        let bytes = s.as_bytes();
        for (i, &item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &s[0..i]; // Return slice
            }
        }
        &s[..]
    }
  4. Understand event object properties during propagation

    When handling events, the event object provides critical information about the propagation state:

    • event.target: The deepest element that triggered the event.
    • event.currentTarget: The element currently processing the event (equivalent to this in the handler).
    • event.eventPhase: The current phase of propagation (1 = capturing, 2 = target, 3 = bubbling).
  5. Understand the Fiber Reconciler and its advantages

    Introduced in React 16, the Fiber Reconciler replaced the Stack Reconciler. It works with the Scheduler to manage component rendering and updates. By using the Fiber node tree (and its return, child, and sibling pointers), the reconciler can traverse the tree more efficiently during the diffing process.

    Key advantages of Fiber scheduling include:

    1. Interruptible Work: Tasks can be sliced into smaller chunks and interrupted.
    2. Priority Management: Tasks can be prioritized, reset, or reused.
    3. Flexible Navigation: The reconciler can move forward and backward between parent and child tasks.
    4. Multiple Elements: The render method can return arrays of elements.
    5. Error Boundaries: Support for handling exceptions via error boundaries.
  6. Common Software Engineering and Architecture Acronyms

    A reference of widely used technical terms in software development, covering APIs, design patterns, and methodologies.
    API: Application Programming Interface
    IDE: Integrated Development Environment
    OOP: Object-Oriented Programming
    CI/CD: Continuous Integration / Continuous Deployment (or Delivery)
    TDD/BDD: Test-Driven Development / Behavior-Driven Development
    JSON: JavaScript Object Notation
    SQL/NoSQL: Structured Query Language / Non-relational databases
    CRUD: Create, Read, Update, Delete (Basic DB operations)
    MVC/MVP/MVVM: Model-View-Controller / Presenter / ViewModel (Design patterns)
    REST: Representational State Transfer (API style)
    CORS: Cross-Origin Resource Sharing
    DRY: Don't Repeat Yourself
    KISS: Keep It Simple, Stupid
    YAGNI: You Ain't Gonna Need It
  7. Understand Nginx server block selection

    Nginx selects a server block based on the listen directives. If multiple server blocks have equally specific listen directives, Nginx evaluates the request's 'Host' header (the domain or IP address the client is attempting to reach) against the server_name directive to determine the match.
  8. Understand Graph data structure basics

    A Graph is a non-linear data structure consisting of a set of vertices (V), also known as nodes, and a set of edges (E), which are the lines or arcs that connect any two nodes. Formally, a graph is denoted as G(V, E).
  9. Manage Server Push in HTTP/2

    HTTP/2 allows servers to proactively push resources to the client before the client explicitly requests them.

    Workflow:

    1. The server sends a PUSH_PROMISE frame containing metadata about the resource it intends to push.
    2. If the client does not need the resource, it can respond with an RST_STREAM frame to cancel the push and avoid wasting bandwidth.
    3. The client can also send a SETTINGS frame to modify the server's push behavior.
  10. Understand the React Diffing Algorithm heuristics

    React uses a heuristic O(n) algorithm to find the minimum difference between two virtual DOM trees. To achieve this performance, it relies on two primary assumptions:

    1. Two elements of different types will produce different trees.
    2. Developers can provide a key prop to hint which child elements are stable across renders.

    To maintain efficiency, React only compares elements at the same level of the tree and does not attempt to match subtrees of different component types across different levels.

  11. Understand React Fiber architecture and time-slicing

    React Fiber is both a data structure and an algorithm designed to enable 'time-slicing'. Unlike traditional recursive rendering which blocks the main thread, Fiber breaks rendering work into small units. This allows React to pause low-priority work (like background updates) to handle high-priority tasks (like user input or animations), ensuring the UI remains responsive.

    Key mechanisms include:

    • Work Loop: A continuous loop that executes work units. It checks the remaining time in the current frame and interrupts work if the time limit is reached.
    • Task Prioritization: Updates are assigned priorities based on their source (e.g., user interactions have higher priority than network requests).
    • Interrupts and Resumption: Because work is broken into Fiber units, React can stop at any point and resume from the exact same location in the next idle period.
    • Scheduling: React uses a custom scheduler (inspired by requestIdleCallback) to manage when work units are processed relative to browser idle time.
  12. Debug Android Chrome pages using macOS

    Debug Android Chrome by utilizing Chrome's remote debugging feature via USB connection.

    Setup Steps:

    1. Android Device: Enable Developer Options (Settings -> About Phone -> tap 'Build Number' several times). In the Developer Options menu, enable "USB Debugging".
    2. Connection: Connect the Android device to the macOS computer via USB.
    3. macOS Chrome: Open a new tab and navigate to chrome://inspect.

    Debugging Process:

    1. In the chrome://inspect page, locate the Android device and the specific Chrome tab you wish to debug.
    2. Click "inspect" to open the Chrome DevTools window.
    3. Use the tools to inspect elements, view console logs, and monitor network requests. Keep the Android device unlocked during the session.