hero image

别犹豫 去行动

Just Do It

Tailwind 快速入门

前言:在接触 Tailwind 的刚开始,并没有感受到它的好处,反而觉得这是一种非常繁琐的事情,非常不适应。为了更好的使用 Tailwindcss,便有了该系列:梳理总结使用规律和用法。

章节系列共分为 7 个小节,每小节开头介绍使用规律,再介绍具体使用方法,各自小节独立可依照需求进行查阅。

Unocss 兼容 Tailwind,因此仅需学习 Tailwind 的用法即可。


Huy大约 2 分钟CSSCSS
再论 Buffer

本文重新梳理一遍 Node.js 中的 Buffer 概念和使用方法。

为什么需要 Buffer?

在 Node.js 中,Buffer 是处理二进制数据的核心对象。JavaScript 本身是基于 Unicode 的字符串处理,但在网络通信、文件操作等场景中,我们经常需要处理原始的二进制数据。Buffer 提供了一种高效的方式来存储和操作这些数据。(Blob 不能直接进行问卷的处理,ArrayBuffer 不能直接操作二进制数据,而 Buffer 则可以直接操作二进制数据)


Huy大约 4 分钟javascriptnode
大文件上传

此前简单梳理过一次大文件的分片上传,这里又重新实现一遍。功能点加上秒传、断点续传、web worker 等。

前端简单用 vite + react19 + antd + axios 实现。后端用 express 实现。代码仓库

功能点总结

  1. 前端分片上传与断点续传

    • 文件切片:用 File.prototype.slice 将大文件分割为多个小块(chunk),每块独立上传。
    • 断点续传:上传前先向后端查询已上传分片,前端只上传未完成的分片,实现断点续传和秒传。
    • 上传进度管理:每个分片上传时通过 onUploadProgress 事件实时更新进度条,整体进度通过所有分片进度的平均值计算。
    • 取消与暂停:利用 axiosCancelToken 实现上传任务的取消和暂停,支持恢复上传。
  2. Web Worker 计算文件 hash `- Web Worker 基础:用 Worker 在浏览器主线程外异步计算大文件 hash,避免 UI 卡顿。

    • 主线程与 Worker 通信:通过 postMessageonmessage 实现主线程与 Worker 的数据交互。
    • SubtleCrypto API:在 Worker 内用 crypto.subtle.digest 计算文件内容的 SHA-256 hash,生成唯一文件名。
  3. React 组件与自定义 Hook

    • 自定义 Hook:用 useDrag 实现拖拽上传、点击上传、文件校验、预览等功能,提升组件复用性。
    • useRef/useState/useEffect:管理 DOM 引用、状态和副作用,确保事件监听和资源释放的正确性。
  4. Node.js 服务端分片处理

    • Express 路由设计:实现 /api/upload(分片上传)、/api/check(查询已上传分片)、/api/merge(合并分片)等接口。
    • 流式处理:用 fs.createReadStreamfs.createWriteStream 实现分片的高效写入和合并,避免大文件占用过多内存。
    • 慢速 Transform 流:自定义 SlowTransform,通过 setTimeout 控制写入速度,方便前端调试进度条和断点续传。
    • 分片合并与 hash 校验:合并所有分片后,流式计算合并文件的 hash,与前端生成的 hash 比较,确保文件完整性。
  5. 性能优化

    • 并行上传与合并:前端并行上传多个分片,后端可并行或串行合并,提升效率。
    • 内存优化:所有大文件操作均采用流式处理,避免内存溢出。
    • 兼容性与用户体验:支持拖拽、点击、进度反馈、错误提示、断点续传等,提升易用性。

Huy大约 3 分钟javascriptnode
再论 ts 体操

长期以来对于 ts 一直停留在「入门」阶段,实际并不理解,ts 为什么在社区中被称为「类型体操」。本文就 ts 类型体操进行梳理,以作回顾。

ts 为什么被称为「类型体操」?

这其实是因为 js 这门语言过于灵活导致的,ts 作为 js 的超集,旨在编译过程中做类型检查,并不会改变 js 的语法。我们可以先看一下其它静态语言的特点:

  1. 简单增加类型系统

    仅仅对定义的变量、函数和类等进行类型声明。类型不匹配时会报错。(这也是笔者此前简单使用 ts 的途径)这种类型系统,过于死板了。比如同一个加法函数,对整数和浮点数需要分别声明,这里以 c++ 为例:

    int add(int a, int b) {
        return a + b;
    }
    
    double add(double a, double b) {
        return a + b;
    }
    
  2. 支持泛型的类型系统

    ts 中也有泛型,泛型旨在通过一种通用的类型,来减少重复的代码。这里不过多介绍。

    T add<T>(T a, T b) {
        return a + b;
    }
    
    add(1,2);
    add(1.111, 2.2222);
    

    java 就是这种类型系统,但是这对于 js 来说还是不够。因为 在 java 中对象都是通过类 new 出来的,但 js 可以凭空创建对象,并且在 ts 中,有时还需要对泛型 T 进行一些逻辑处理。由此诞生了 ts 这种「支持类型编程的类型系统」

  3. 支持类型编程的类型系统

    在 ts 中,经常能看到对传入的类型参数(泛型)做各种逻辑运算,产生新的类型,这就是类型编程。

    比如下面这个类型体操题目:实现一个类型 Flatten<T>,把嵌套的数组类型展开成一个一维数组:

    type Flatten<T> = T extends [infer First, ...infer Rest]
      ? [...Flatten<First>, ...Flatten<Rest>]
      : [T]
    
    type Result = Flatten<[1, [2, [3, 4]], 5]>
    // 结果是 [1, 2, 3, 4, 5]
    

    这就像在类型层面实现了一个“数组扁平化”,完全不依赖 JS 运行逻辑,全靠类型推导实现,非常绕脑,但也很优雅。


Huy大约 3 分钟javascripttypescript
从 Iterator 迭代器到 Generator 生成器

迭代器的协议规范是:一个对象必须实现一个特定的接口,该接口包含一个名为 next 的方法,该方法返回一个对象,该对象包含两个属性:valuedone

value 属性表示迭代器返回的当前值,done 属性是一个布尔值,表示迭代器是否已经迭代完所有元素。

{
  value: any,
  done: boolean
}

Huy大约 6 分钟javascriptjavascript
Promise 的状态吸收

一直以来,对 Promise 的状态吸收问题,我都没有很好理解,今天终于理顺了,因此记录一下。

由于 Promise 规范中对这块没有详细定义,因此这里的 Promise 处理机制均是基于 V8 引擎的。

Promise 回顾

Promise 有三种状态:pendingfulfilledrejected。当使用 resolvereject 时,Promise 的状态会发生变化,但一旦状态发生变化,就不会再变。


Huy大约 4 分钟javascriptjavascript
React之MobX

简单入门一下 Mobx~

MobX 是一个用于 JavaScript 应用程序的状态管理库,它通过响应式编程原则简化和扩展了状态管理。它在 React 应用程序中特别受欢迎,但也可以与任何 JavaScript 框架或库一起使用。

Mobx
Mobx

Huy大约 6 分钟框架React
Koa 异步调用中间件的本质

Koa 是通过将中间件组织成一个“洋葱模型”(Onion Model),并使用 async/awaitPromise 链式执行机制实现异步中间件的。

核心机制

  1. 中间件存储:

    • 中间件被存储为一个数组(middlewares)。
    • 每个中间件是一个函数,接受 ctx(上下文)和 next(下一个中间件的执行函数)作为参数。
  2. 组合中间件(compose):

    • Koa 使用一个函数(类似于 compose)将多个中间件组合成一个函数,并按顺序执行。
    • 每个中间件调用 await next() 来手动控制下一个中间件的执行时机。
  3. 递归调用:

    • 当一个中间件调用 await next() 时,它会等待下一个中间件执行完成后再继续执行当前中间件后面的逻辑。

Huy大约 2 分钟javascriptnode
React之技术细节

这里用于梳理 React 的一些技术实现细节,以作技术回顾。

setState 的更新逻辑

这里主要讨论的是 React18 以前的策略。React18 之后,全部采用异步调用。可见setstate-的更新逻辑

React18 以前,setState 的更新逻辑有时是同步的有时是异步的,这取决于调用 setState 的环境。实际上,在 React 控制之内的事件处理过程中,setState 是异步的,而在 React 控制之外的事件处理过程中,setState 是同步的。


Huy大约 2 分钟框架React
Cesium Property 属性机制

在此前系列中,笔者梳理了 Cesium 的基本使用方法,但是为了更进阶了解 Cesium,我们需要了解 Cesium 的核心机制,其中之一就是 Property 属性机制。

先总览一遍 Property 类型分类。

Property 类型
Property 类型

Huy大约 12 分钟框架gis
2
3
4
5
...
18

Yesterday is history, tomorrow is a mystery, today is a gift of God, which is why we call it the present.