Skip to main content

JS await 基础入门类

· 4 min read

JS 中 async/await 不是新功能,是 Promise 的语法糖——本质还是回调。

掌握 await 只需记住 件事:

  1. await 只能用在 async 函数里,async 函数永远返回 Promise
  2. await 会"暂停"当前函数,但不会阻塞主线程,其他代码照常跑
  3. 抛错用 try/catch,忘记 try/catch 会导致 UnhandledPromiseRejection

最佳实践:并发请求用 Promise.all,别串行 await,慢到怀疑人生。

JS await 异常捕获类

· 4 min read

JavaScript 异步异常处理 种姿势,try/catch 嵌套地狱 最常见也最糟糕。

  1. try/catch 包 await:层层嵌套,业务和错误处理混成一坨
  2. .catch() 链式:返回 undefined 难以判断错误来源
  3. 元组解构 [err, data]:Go 风格,推荐

封装一个 to(promise) 工具函数,10 行代码消灭所有 try/catch,错误处理变成一行 if (err) return

关键:业务错误用元组、致命错误仍要抛,别用工具类把所有异常都吞掉。

JS await 执行顺序

· 4 min read

JavaScript 中 await 的执行顺序,是面试高频题,也是写异步代码最容易踩的坑。

  1. await 后面的表达式 立即同步执行,只有等号左边的赋值才被推入微任务队列
  2. await 本质是 Promise.then 的语法糖,每个 await 至少消耗 个微任务 tick
  3. 循环里 await 串行执行,N 个请求耗时 N 倍,必须用 Promise.all 并发
  4. 同步代码 → 微任务(await/then)→ 宏任务(setTimeout)的顺序永远不变
  5. 判断输出顺序的口诀:先跑同步,再清微任务,最后才轮到宏任务

ClaudeCode 客户端消息流是如何确保按序输出的?

· 6 min read

ClaudeCode 客户端消息流的有序性,本质上是 单写者 + 显式序号 + 受控并发 换来的工程纪律,不是靠运行时去猜消息该怎么排。

要点拆解:

  1. 所有 stream 事件先汇入统一写入通道,由 序号 决定渲染顺序,不按到达时间。
  2. 工具并发被框死在 读可并行、写必串行 的边界内。
  3. UI 层只信任已经定序的快照,从不直接消费裸 SSE,否则就是乱序事故的源头。
  4. 回合作为原子单位,失败整体丢弃,不修补半截回合。

理解这套规则,比追着 SDK 文档更有用。

OpenCode 客户端消息流是如何确保按序输出的?

· 6 min read

OpenCode 客户端保证消息有序,靠的不是排序算法,而是 "按 partID 分桶 + 桶内就地更新" 的状态合并模型。

核心设计 点:

  1. 每个 part 由服务端分配全局唯一 id创建顺序 = 渲染顺序
  2. 后续 part.updated 事件按 id 就地覆盖,不动 partOrder
  3. 断线重连先拉快照、再续 SSE,幂等更新天然无缝衔接

反面教材:早期每次更新都 setMessages([...messages]) 全量复制,消息一长 CPU 直接飙满。Streaming UI 的性能瓶颈从来不在网络,而在前端的更新粒度。

DOM 中 closest 方法的作用是什么?举个例子

· 5 min read

closest() 是 DOM 元素方法,从自身开始沿父链向上查找第一个匹配 CSS 选择器的元素。

  1. 查找方向:自身 → 父 → 祖父 → <html>,找到即返回,否则返回 null
  2. 包含自身:当前元素就匹配时直接返回它,不是从父级才开始
  3. 接受任意选择器:标签、类、属性、伪类、复合选择器都支持
  4. 核心场景:事件委托、点击外部关闭、从子节点反查所属组件根
  5. 替代写法:等价于手写 while (el && !el.matches(sel)) el = el.parentElement

最佳实践:原生事件委托里只要涉及"从点击目标反查父级",优先用 closest(),别再手写 parentElement 循环。IE 不支持,老项目需 polyfill。

Karpathy 4 条规则是什么?

· 3 min read

Andrej Karpathy 提出的 AI Agent 开发 4 条核心规则,目标是把 Claude 犯错率从 41% 压到 3%:

  1. 先想再写(Think Before Coding):显式说出假设,有歧义时先问,别猜。存在更简单方案时主动推后。

  2. 简单优先(Simplicity First):最小可用代码,不写没被要求的功能,没有"以防万一"的抽象。

  3. 外科手术式修改(Surgical Changes):只动该动的,不顺手"优化"旁边的代码、注释或格式。

  4. 目标驱动执行(Goal-Driven Execution):定义成功标准,循环到验证通过,不告诉 Claude 走哪些步骤,告诉它什么叫"做完了"。

只靠这 4 条只能关闭约 40% 的常见失误,剩下 60% 需要更进阶的规则补充。

Tailwindcss preflight 是做什么用的?

· 3 min read

Preflight 是 Tailwind CSS 内置的「基础样式重置/规范化」工具,基于 modern-normalize,抹平浏览器默认样式差异,统一基线,让你只用工具类就能一致地控制布局与外观。

核心做了 5 件事:

  1. 全局 box-sizing:所有元素默认 border-box,保证 padding/border 不会撑宽元素

  2. 清空默认边距:清除 h1~h6、p、ul、blockquote 等默认 margin/padding,避免意外留白

  3. 语义化但无外观:标题不再自带大小/加粗,列表去掉项目符号,只保留语义

  4. 媒体默认 block:img、svg、video、canvas 默认 display: block,避免底部空白间隙

  5. 表单元素统一:修复 Safari 等浏览器的控件样式差异,继承字体

注入到 base 层,优先级低于 components/utilities,完全不影响你写的样式。

Linux 软连接和硬连接的区别?

· 3 min read

Linux 中有 2 种链接方式,理解它们的区别是掌握文件系统的基础:

  1. 硬链接:同一个文件,多个文件名(共用 inode),删除本体不影响其他链接

  2. 软链接(符号链接):快捷方式,存储路径指向原文件,删本体就失效

硬链接不能跨分区、不能链接目录;软链接可以跨分区、可以链接目录。

Code inspector 代码定位的插件原理是什么?

· 4 min read

Code Inspector 是一款 IDE 自动跳转插件,让你在浏览器中点击元素就能直接跳转到对应的源码位置。核心原理分为 3 步:

  1. 编译期插桩:打包时用 AST 解析,给每个 DOM 元素注入源码位置属性

  2. 运行时监听:浏览器端监听快捷键+点击,从 DOM 取出埋点信息

  3. 本地服务调度:向本地服务发送请求,调用 IDE 命令打开文件并定位

纯编译层实现,零业务代码侵入,兼容 Vue/React/原生,适配主流编辑器。