普通视图

发现新文章,点击刷新页面。
昨天以前news view

Cloudflare Workers 处理函数计算中的 CPU 性能问题

2025年10月16日 08:00

原文: https://blog.cloudflare.com/unpacking-cloudflare-workers-cpu-performance-benchmarks/

原文主要讲述了 Cloudflare Workers 和 Vercel 在 CPU 性能方面的一些对比, 在应用上的重点是 React SSR 类应用的 TTFB 测试.

其中我认为的一些关键点是:

  1. 函数计算的调度问题 (非 CPU 计算消耗).
  2. Node.js 对 V8 调参导致的性能问题.
  3. 代码中处理 buffer 不当导致的内存占用及后续 GC 的问题.
  4. Node.js 的非 Web 标准化问题, 比如 Streams API.
  5. Cloudflare Workers 团队在解决自己问题的过程中如果发现了生态问题, 甚至竟品问题, 也期望一并解决.

我们的核心业务均由函数计算承担, 在此处有许多经验. 函数计算中的几大时间消耗为:

  1. 调度时间
  2. (可能) 冷启动时间
  3. 执行时间 (被计算为 CPU 消耗)

一般来说, “执行时间” 与函数计算无关. 函数计算需要重点考虑的, 是 “调度时间” 和 “冷启动时间”.

作为用户, 一些配置会影响到调度时间, 比如使用什么操作系统, 是否要接入 VPC 等.

想要优化冷启动时间, 则应该将重点放在 “架构” 上. 一般来说, 解释型语言的冷启动时间会小很多. 比如函数计算一般使用 Python, JavaScript, 而不使用 Java.

另外一种优化就是 “预热”, 可以理解为提前启动. 但是预热是有成本开销的, 并且我认为预热是有悖于函数计算模式的. 我更倾向于减少冷启动时间, 而不是预热.

Cloudflare Workers 针对调度问题的优化, 是所有用户乐于看到的. 加量不加价, 并且默认生效, 用户无需任何额外配置.

Node.js 的非 Web 标准化问题, 就是我们几年前选型 Deno, 而非 Node.js 的关键原因. 即便我们不是全栈团队, 也希望在 JS 领域, 技术栈尽量统一, 减少不必要的消耗.

最后, 看到问题就想要去解决, 无论这个问题是否影响到自身利益, 这不仅是工程师应该有的素质, 也是每一个人应该有的素质. 就像走路时如果看到了脚边的垃圾, 可以顺手捡起来扔到垃圾箱中.

不是鼓励大家无偿奉献, 而是举手之劳, 何乐而不为? 每个人多付出 1%, 就会让整个世界进步不只 100%.

Deno Fresh 2.x 支持 Vite

2025年9月3日 08:00

Update:

  • 目前 Fresh 文档默认的版本已经是 2.x.

在许多前端项目中, 都使用 Vite 处理构建流程.

对于 Deno 团队来说, Node.js 生态下的项目, 如 ESLint 等一直是受到排斥的. 基于零配置易用性及性能考虑, Deno 会在相关领域重做一套工具, 比如 deno lint, fmt.

不过随着 Deno 对 Node.js 兼容性的增强, Deno 团队对 Node.js 生态也越来越包容.

现在, Deno 官方项目 Fresh 会主动集成 Vite (而不是 deno compile 或者刚刚恢复的 deno bundle).

官方 Blog 文章: Fresh 2.0 Graduates to Beta, Adds Vite Support

deno compile 一直没有实现一键打包 Deno Fresh 项目. 或许跟 Fresh 特殊的路由策略有关.

但是 Vite 是支持在编译时处理动态路由并且打包的, 也支持代码分割.

在官方文章中, 主要介绍了下面几个功能:

  1. 借助 Vite 的 岛内热加载, 而不是全页热加载.
  2. 借助 Vite 的 服务器代码打包, 加快启动时间.
  3. 借助 Vite 的 React 别名.
  4. 回归的 Head 组件

Fresh 2.0 正式进入 beta, 不再会有重大变动. 现在就可以尝试了.

TypeScript 使用 Go 进行了重构

2025年3月13日 08:00

我在 GitHub 上看到了 @ahejlsberg 为 https://github.com/microsoft/typescript-go project 点了 star.

在 11 日, TypeScript 官方博客发布了一篇名为 A 10x Faster TypeScript 的文章, 介绍了微软正在使用 Go 语言重写 TypeScript 编译器, 并取得了显著的性能提升.

Anders Hejlsberg 是 TypeScript 的主要设计者, 也是 C# 和 Delphi 的最初设计者. 为了解决性能问题, 他带领的团队没有使用 C# 或者 Rust 等语言, 而是使用了 Go, 在社区中引起了一些质疑的声音.

我认为最重要的原因就是新项目是 “port”, 而不是 “rewrite”. 在一众备选项中, Go 的语法是最容易从 TypeScript 迁移过去的.

我理解微软开发团队这样的做法, 比如 VS Code 在宣传的时候也会使用 create-react-app 这样的 Facebook 项目来宣传. 可见, 微软想要与技术社区进行融合的意愿很强.

为什么选择 Go?

根据 TypeScript 官方博客 A 10x Faster TypeScript 的介绍, 微软选择 Go 语言进行编译器移植的原因主要包括:

  1. 可维护性: Go 语言拥有高效且易于理解的垃圾收集器, 简单易学的语法以及良好的 开发者生态系统, 使得维护大型代码库更加容易
  2. 性能优势: Go 编译器的多方面优化使其非常适合构建编译器这类程序, 并且与 JavaScript 版本相比, 能够显著提高编译速度
  3. 跨平台能力: Go 的原生编译特性让 TypeScript 编译器能够轻松构建为适用于 各种操作系统的单一二进制文件
  4. 开发效率: Go 语言的错误处理模式, 简单的语法和快速的编译时间, 让开发团队能够快速迭代和实现功能

C/C++ 的跨平台能力较差, 比如不支持简单编译为各个平台的单一二进制文件. 而 Rust 的内存安全模型过于复杂, 不适合作为 port 项目. C# 应该更多是语言特性上与 TypeScript 有区别, 严格的 OOP 风格不适合作为 port.

当前进展与兼容性

repo 的 init commit 是 2024-10-01 https://github.com/microsoft/typescript-go/commit/cdcc0cb808d8ad0c91d9520edac3d815bff92514, 仅用大概半年的时间, 就取得了显著的进展, 据说完成了 80% 的代码迁移.

根据 GitHub 仓库的 README 文档, TypeScript 的 Go 原生移植版(称为”TypeScript 7”) 目前仍处于积极开发阶段. 当前已完成的功能包括:

  • 程序创建(读取 lib, target, reference 等配置)
  • 解析/扫描(读取源文本并确定语法结构)
  • 命令行和 tsconfig.json 解析
  • 类型解析和类型检查

为了实现迁移, 微软会在 TypeScript 6 (仍然是 TypeScript) 的时候, 做一些功能调整, 以保证将来发布 TypeScript 7 (Go 版本) 时大家可以无缝迁移.

TypeScript 6 和 TypeScript 7 的 API 是完全兼容的, 所以开发者可以随时升级或降级. 在 TypeScript 7 被完全接受前, TypeScript 6 会继续开发, 以作为备选.

社区反应

这一项目在公布后引起了开发社区的广泛关注, 截至目前 GitHub 仓库已获得超过 11.9k 的星标. 许多开发者对于提升 TypeScript 性能的前景表示期待, 特别是那些处理大型 代码库的团队.

社区讨论主要集中在性能提升, 工具链兼容性以及 为什么选择 Go 而非其他语言 (如 Rust) 上.

相关链接

软件架构与实验艺术

2024年12月25日 08:00

:bulb: 原文链接: https://www.infoq.com/articles/architecture-experimentation/

在软件架构领域, 我们经常会做出许多决策. 有些决策会带来积极的影响, 而有些则会产生消极的后果. 在做出这些决策时, 我们往往会陷入两难境地:

  1. 我们希望做出正确的决策
  2. 我们无法预知未来

这就像是在玩一个概率游戏. 我们可以通过研究, 分析和经验来提高做出好决策的概率, 但我们永远无法完全确定某个决策就一定是正确的.

通过实验来验证决策

在这种情况下, 唯一合理的方法就是通过实验来验证我们的决策. 这意味着:

  • 承认我们可能会犯错
  • 设计实验来测试我们的假设
  • 收集数据来验证决策的效果
  • 准备好在需要时调整或改变方向

让我给您举个例子. 假设您正在开发一个新的在线零售平台, 需要决定使用哪种数据库技术. 您可能会考虑:

  • 关系型数据库(如 PostgreSQL)
  • NoSQL 解决方案(如 MongoDB)
  • 分布式数据存储系统

与其仅仅基于理论讨论做出选择, 不如设计一些实验来测试每种选项在您的具体场景中的表现.

最小可行架构(MVA)

最小可行架构(MVA)是一个重要概念, 它强调:

  1. 从最简单的可工作方案开始
  2. 通过实验逐步验证和改进
  3. 在实际使用中收集反馈
  4. 根据反馈调整架构决策

MVA 与最小可行产品(MVP)的理念相似, 但关注点是技术架构而不是业务功能.

实验的重要性

在软件开发中, 每个产品发布实际上都是一系列实验的集合. 这些实验不仅关于产品功能, 还包括:

  1. 技术可行性 - 选择的技术方案是否真的能够实现预期目标
  2. 可维护性 - 系统是否容易维护和更新
  3. 可扩展性 - 系统能否应对增长需求
  4. 运营成本 - 解决方案在财务上是否可持续

实验设计的关键要素

好的架构实验应该包含以下要素:

  1. 明确的假设
    • 清晰陈述我们认为会发生什么
    • 为什么我们认为会这样
    • 这些假设基于什么依据
  2. 可测量的目标
    • 具体的性能指标
    • 明确的成功标准
    • 可量化的结果
  3. 实验方法
    • 如何进行测试
    • 需要收集什么数据
    • 如何收集这些数据
  4. 风险控制
    • 失败后的回退方案
    • 对系统其他部分的影响评估
    • 如何隔离实验的影响范围
  5. 时间框架
    • 实验持续时间
    • 关键时间节点
    • 评估周期

实验的实际案例

让我们看一个具体的例子:

假设一个团队正在考虑将单体应用迁移到微服务架构。他们可以这样设计实验:

实验名称:核心功能微服务迁移测试

假设:

  • 将订单处理模块拆分为独立微服务将提高系统扩展性
  • 服务间通信不会显著影响性能

测试方法:

  1. 选择一个非关键时段
  2. 将订单处理模块拆分为独立服务
  3. 部署到生产环境的隔离区域
  4. 使用影子流量进行测试

成功标准:

  • 响应时间不超过现有系统的 120%
  • 系统资源使用率保持在可接受范围
  • 服务间通信延迟低于 50ms

回退计划:

  • 保留原有系统运行
  • 准备快速切换回原架构的脚本
  • 预设故障转移机制

实验的陷阱

在进行架构实验时,需要注意避免以下常见陷阱:

  1. 范围过大
    • 试图一次性解决太多问题
    • 实验周期过长
    • 难以确定具体问题的根源
  2. 指标模糊
    • 成功标准不够具体
    • 缺乏量化指标
    • 难以做出客观评判
  3. 忽视成本
    • 未考虑实验失败的代价
    • 忽视长期维护成本
    • 低估迁移成本

实验驱动的架构演进

渐进式变更

在进行架构演进时,采用渐进式的变更策略非常重要:

  1. 小步快跑
    • 将大型变更分解成小的、可管理的步骤
    • 每个步骤都可以独立验证
    • 降低每次变更的风险
  2. 持续验证
    • 在每个阶段收集反馈
    • 及时发现问题并调整
    • 建立度量标准来评估进展
  3. 保持可逆性
    • 确保每个变更都是可回退的
    • 维护多个系统版本的能力
    • 准备应急方案

实验的生命周期

一个完整的架构实验生命周期包括:

  1. 规划阶段
    • 定义实验目标
    • 设计实验方案
    • 确定评估标准
  2. 准备阶段
    • 搭建测试环境
    • 准备监控工具
    • 建立基准数据
  3. 执行阶段
    • 实施变更
    • 收集数据
    • 监控系统
  4. 评估阶段
    • 分析结果
    • 总结经验
    • 决定下一步
  5. 调整阶段
    • 根据结果优化
    • 扩大或缩小范围
    • 准备下一轮实验

实验文化的建立

要在团队中建立良好的实验文化:

  1. 鼓励创新
    • 接受失败作为学习的一部分
    • 奖励大胆尝试
    • 分享经验教训
  2. 数据驱动
    • 基于事实做决策
    • 建立度量体系
    • 重视客观反馈
  3. 持续学习
    • 定期回顾实验结果
    • 记录和分享知识
    • 调整实验方法

实际案例研究

让我们看一个更详细的案例:

案例:缓存层改造实验

背景:

  • 现有系统使用单机缓存
  • 随着用户增长,出现性能瓶颈
  • 考虑迁移到分布式缓存

实验设计:

  1. 第一阶段:小规模测试
    • 选择非核心业务模块
    • 部署分布式缓存集群
    • 监控性能和稳定性
  2. 第二阶段:负载测试
    • 模拟生产环境负载
    • 测试故障转移
    • 评估运维复杂度
  3. 第三阶段:灰度发布
    • 逐步迁移业务模块
    • 观察系统表现
    • 收集用户反馈

评估指标:

  • 缓存命中率
  • 响应时间
  • 系统资源使用
  • 运维成本

长期架构演进

平衡短期与长期目标

在进行架构实验时,需要考虑:

  1. 短期收益
    • 立即可见的性能提升
    • 快速解决当前问题
    • 用户直接感受的改进
  2. 长期影响
    • 技术债务的累积
    • 维护成本的变化
    • 未来的扩展性
  3. 权衡因素
    • 开发速度 vs 代码质量
    • 创新 vs 稳定性
    • 灵活性 vs 复杂度

持续改进的策略

为确保架构能持续演进:

  1. 建立反馈循环
    • 监控系统性能
    • 收集用户反馈
    • 分析运营数据
  2. 定期评估
    • 架构审查会议
    • 性能基准测试
    • 技术栈评估
  3. 适应性调整
    • 根据业务需求调整
    • 采纳新技术
    • 淘汰过时组件

常见陷阱和解决方案

在长期架构演进中常见的问题:

  1. 过度工程
    • 问题:构建超出实际需求的复杂系统
    • 解决:坚持”足够好”原则,循序渐进
  2. 决策惯性
    • 问题:因为历史原因继续使用次优方案
    • 解决:定期重新评估决策,保持开放心态
  3. 忽视维护性
    • 问题:只关注功能实现,忽视后期维护
    • 解决:将可维护性作为架构决策的关键指标

文档和知识管理

保持良好的文档习惯:

  1. 决策记录
    • 记录重要决策的原因
    • 记录被否决的方案
    • 保存相关讨论内容
  2. 实验日志
    • 详细的实验过程
    • 数据收集方法
    • 结果分析
  3. 经验教训
    • 成功和失败的案例
    • 意外情况的处理
    • 改进建议

团队协作

有效的团队协作对实验成功至关重要:

  1. 沟通机制
    • 定期架构讨论会
    • 技术评审流程
    • 知识分享会议
  2. 角色分工
    • 实验负责人
    • 监控人员
    • 评估团队
  3. 决策流程
    • 提案机制
    • 评审流程
    • 实施审批

结论与展望

实验驱动的架构方法总结

成功的架构实验方法建立在以下基础之上:

  1. 实验思维
    • 承认不确定性的存在
    • 愿意通过实验来验证假设
    • 对失败保持开放态度
  2. 系统方法

    • 明确的实验流程
    • 可靠的数据收集
    • 客观的评估标准
    • 完善的反馈机制
  3. 持续改进
    • 不断优化实验方法
    • 积累经验教训
    • 调整决策流程

未来趋势

架构实验在未来可能的发展方向:

  1. 自动化实验
    • 自动化测试和部署
    • AI 辅助决策
    • 智能监控和分析
  2. 混沌工程
    • 主动故障注入
    • 弹性测试
    • 系统边界探索
  3. 实验工具链
    • 集成的实验平台
    • 可视化分析工具
    • 协作决策系统

最佳实践建议

给架构师和开发团队的建议:

  1. 开始时要小
    • 从小规模实验开始
    • 逐步增加复杂度
    • 积累经验和信心
  2. 保持警惕
    • 持续监控系统
    • 注意早期警告信号
    • 及时调整方向
  3. 分享知识
    • 记录和分享经验
    • 建立知识库
    • 促进团队学习

结束语

架构实验不是一次性的活动,而是持续改进的过程。成功的关键在于:

  • 建立正确的实验文化
  • 采用系统的方法论
  • 保持学习和适应的能力
  • 重视团队协作和知识共享

通过实验驱动的方法,我们可以:

  1. 降低架构决策的风险
  2. 提高系统的可靠性
  3. 促进团队的成长
  4. 推动技术的创新

最终,架构实验的目标是帮助我们构建更好的系统,为用户创造更大的价值。

参考资料

  • 相关书籍和文章推荐
  • 实用工具和框架
  • 案例研究和最佳实践
  • 社区资源和讨论组

这就是全文的完整翻译. 这篇文章深入探讨了软件架构中实验的重要性, 以及如何通过系统化的方法来进行架构实验和演进. 希望这个翻译对您有帮助!

OpenAI 12 Days 总结

2024年12月22日 08:00
中文版本

发布会

OpenAI 最新办了一场 12 天 “发布会”: https://openai.com/12-days/

国内文章: https://www.infoq.cn/article/WXPMviOWQ1LNZhqZC5ZE

总结这几天的内容, 核心为:

  1. ChatGPT Pro 服务, 200 美元/月 (Day 1)
  2. 正式发布 o1 模型 (Day 1, 9)
  3. 正式发布 Sora 模型 (Day 3)
  4. 技术预览 (微调与 o3 模型) (Day 2, 12)
  5. 更多应用层面的更新 (创作者助手, 苹果集成, 会话整理, 多媒体信息, 搜索, 电话版 ChatGPT 等) (Day 4, 5, 6, 7, 8, 10, 11)

应用层面的创建无疑是收入的一个重要增长点. 但是对于 OpenAI 来说, 应用不是撒手锏, 模型才是.

所以这里面除了影响营收的 Pro 版本的收费, Sam 仅参加了模型相关发布 o1, Sora, o3.

模型

感觉有意义的点还不如 Ilya Sutskever 在 NeurIPS 2024 的演讲.

不过都在一个发力: 逻辑性

AI 的幻觉问题比较严重, 这个问题其实也是 AI 缺乏逻辑性的一个表现.

可是人类的神经元就可以让自己有逻辑, 那 AI 为什么不能?

这就是 AI 的下一步方向, 不是找更多数据, 而是利用当前数据如何让 “逻辑性” 显现.

这种逻辑性, 而非知识性的问题我们也遇到了. 针对一些稍微复杂一点的逻辑问题, 当前主流模型都回答得不好 (应该说不对).

English Version

Launch Event

OpenAI recently held a 12-day “launch event”: https://openai.com/12-days/

Key announcements during these days include:

  1. ChatGPT Pro service at $200/month (Day 1)
  2. Official release of o1 model (Day 1, 9)
  3. Official release of Sora model (Day 3)
  4. Technical previews (fine-tuning and o3 model) (Day 2, 12)
  5. More application-level updates (Creator Assistant, Apple integration, conversation organization, multimedia handling, search, phone version of ChatGPT, etc.) (Day 4, 5, 6, 7, 8, 10, 11)

Application-level innovations are undoubtedly an important growth point for revenue. However, for OpenAI, applications are not their trump card - models are.

That’s why among all these announcements, Sam only participated in model-related releases: o1, Sora, and o3.

Models

The meaningful points here are not as significant as Ilya Sutskever’s speech at NeurIPS 2024.

However, they all focus on one direction: logical reasoning

AI’s hallucination problem is quite serious, which is actually a manifestation of AI’s lack of logical reasoning ability.

Human neurons can enable logical thinking, so why can’t AI?

This is the next direction for AI - not finding more data, but utilizing existing data to manifest “logical reasoning”.

We’ve also encountered this issue of logical reasoning versus knowledge. Current mainstream models don’t perform well (or more accurately, don’t perform correctly) on slightly more complex logical problems.

Deno 使用实践与总结

2024年12月19日 08:00
中文版本

Deno 中的依赖管理

  1. 直接使用 import 进行相对路径的文件引用.
  2. 直接使用 import 进行 HTTPS 绝对路径的文件引用. 2.1. 比如使用 deno.land 的包 (仅限公共包). 2.2. 比如使用 GitHub 的包 (raw.githubusercontent.com). 2.3. 如 https://esm.sh/ 2.4. 如 https://jspm.org/ 2.5. 如 https://www.skypack.dev/ 2.6. 如 https://www.jsdelivr.com/esm
  3. 引用 npm 包.
  4. 引用 jsr 包. (仅限公共包).

jsr.io 包仓库

jsr.io 是 Deno 官方团队开发维护的一个包仓库, 可以同时发布为 Deno 和 Node.js 的包.

如果没有 jsr.io, 如果一个包想要同时支持 Deno 和 Node.js, 那么需要维护两套代码.

如果不想维护两套代码, 则可以构建时魔改代码, 但会受到许多约束:

  1. 转为 Node.js 包的时候移除 .ts 后缀名.
  2. 无法添加 deno 依赖.
  3. 无法添加 Node.js 依赖.

jsr.io 的包可以同时支持 Deno 和 Node.js, 解决了上述痛点. 但是 jsr.io 有两大问题:

  1. jsr.io 不支持 HTTP 绝对路径的文件引用.
  2. jsr.io (暂时) 不支持私有包. https://github.com/jsr-io/jsr/issues/203

Deno 运行时特点

Deno 中的浮点误差

虽然 Deno 的一大核心是 V8 引擎, 但 Deno 的运行时针对浮点计算进行了特殊处理.

比如我们要做下面的浮点运算: 1.1 * 100

  • Deno 2.1.4 (since 1.9.2) -> 110
  • Chrome 131 (since 90) -> 110.00000000000001
  • Node.js v20.11.0 -> 110.00000000000001

Deno 的运行时似乎在刻意避免浮点误差.

Node.js 兼容性

Node.js 的生态非常庞大, Deno 想要扩大运行时市场份额, 需要为在 Node.js 环境下开发的软件提供兼容性.

在 Deno 2.x 版本中, Deno 已经尽量支持了许多 Node.js 的包.

但是这种支持仍然有限:

  1. localAddress 参数没有效果. https://github.com/denoland/deno/issues/24153
  2. 更多兼容问题见 issue 列表
  3. Deno 支持不完善的 Node.js 功能
  4. Deno 暂不支持的 Node.js 功能

原生 Deno API

目前 Deno 提供的 API 仍有限, 比如有下面的问题:

  1. 网络请求时不支持选择网卡. https://github.com/denoland/deno/issues/27376
  2. 不支持 brotli 压缩. (但通过 Node.js 兼容包可实现)
English Version

Dependency Management in Deno

  1. Direct file imports using relative paths.
  2. Direct file imports using HTTPS absolute paths. 2.1. Using packages from deno.land (public packages only). 2.2. Using packages from GitHub (raw.githubusercontent.com). 2.3. From https://esm.sh/ 2.4. From https://jspm.org/ 2.5. From https://www.skypack.dev/ 2.6. From https://www.jsdelivr.com/esm
  3. Importing npm packages.
  4. Importing jsr packages (public packages only).

jsr.io

jsr.io is a package registry developed and maintained by the Deno official team, allowing packages to be published for both Deno and Node.js.

Without jsr.io, supporting both Deno and Node.js would require maintaining two separate codebases.

To avoid maintaining dual codebases, code could be transformed during build time, but with several constraints:

  1. Removing .ts extensions when converting to Node.js packages.
  2. Cannot add Deno dependencies.
  3. Cannot add Node.js dependencies.

jsr.io packages can support both Deno and Node.js, solving these pain points. However, jsr.io has two major issues:

  1. jsr.io doesn’t support HTTP absolute path imports.
  2. jsr.io (temporarily) doesn’t support private packages. https://github.com/jsr-io/jsr/issues/203

Deno Runtime Characteristics

Floating Point Precision in Deno

Although V8 engine is a core component of Deno, the runtime handles floating-point calculations differently.

For example, let’s consider this floating-point calculation: 1.1 * 100

  • Deno 2.1.4 (since 1.9.2) -> 110
  • Chrome 131 (since 90) -> 110.00000000000001
  • Node.js v20.11.0 -> 110.00000000000001

Deno’s runtime appears to deliberately avoid floating-point errors.

Node.js Compatibility

With Node.js’s vast ecosystem, Deno needs to provide compatibility for software developed in Node.js environment to expand its runtime market share.

In Deno 2.x, many Node.js packages are supported.

However, this support is still limited:

  1. localAddress parameter has no effect. https://github.com/denoland/deno/issues/24153
  2. More compatibility issues in the issue list
  3. Partially supported Node.js features in Deno
  4. Currently unsupported Node.js features in Deno

Deno API

Currently, Deno’s API offerings are still limited, with issues such as:

  1. No support for network interface selection in network requests. https://github.com/denoland/deno/issues/27376
  2. No support for brotli compression. (though achievable through Node.js compatibility packages)

谈 Alex Russell 谈 React

2024年12月11日 08:00

我看了部分 Alex Russell 的原文, 完整看了这篇翻译文章.

下面是我的一些看法:

Frameworkism

Web 开发者并不是主动要被框架束缚, 在前端 (客户端) 开发中, Android, iOS, 微信小程序, 鸿蒙应用等, 都在实现更多前端功能的前提下限制了前端的开发流. 而 Web 自身的设计在相同场景下相比其他前端开发技术栈来说交互严重不足.

那我们有交互需求的时候应该怎么办? 直接操作 DOM 太繁琐, 并不是一种现代化的方案, 所以我们在 Web 的基础上需要框架, 而不是直接写 HTML + JS + CSS.

Why SPA

SPA 不是必要的, 但是 Web 应用而不是 Web 网页是必要的, 因为将 Web 作为应用会让整体前端技术栈层次更清晰. 而 SPA 是实现 Web 应用的一种直观的方式, 与其他端开发的架构变得类似.

隔行如隔山, 我相信 Russell 并没有站在一个项目整体的立场, 并且没有考虑许多工程化的概念, 比如 Hydration. Russell 低估了许多应用交互的复杂性.

我更倾向于让 Web 承载更多应用的场景, 而不是让 Web 承载更多网页的场景. 许多软件功能都是不必要使用 “系统级别应用” 的, 借由 PWA 等概念, Web 可以承载更多这样的功能.

Why React

不可否认社会上存在许多 “随大流” 的想法. 但 Russell 这篇文章的受众不会是随大流想法. 如果真的没有思考, 是不会去看 Russell 的文章的.

那我们为什么使用 React? 简单来说有三点:

  1. React 可以实现我们的需求. React 提供了一套简单的原则, 状态数据 + JSX.
  2. React 简单易懂. 在工程上有足够的优势.
  3. 生态好. 因为 React 有先发优势, 可能也因为 React 在其他方面有优势.

并不是因为:

  1. “Facebook 用了 React, 所以我们用肯定没问题.” React 是 Facebook 的产物, 但是 React 之所以成为一个开源项目, 是因为 React 解决的是一个通用且朴素的问题.
  2. “React 是行业标准.” 我们也不认为 React 是标准, 但不可否认 React 对其他许多流行库造成了深远的影响.
  3. “React 更容易被招聘.” 一方面, React 并不复杂, 另一方面, React 在我们的环境下并没有明显的招聘优势.

在 Russell 介绍其他框架的时候, 我一开始难以理解 “React, Angular, etc.” 中的 “etc.” 不包含 Vue 等.

后来我明白了, Russell 的角度从来都不是 Web 开发者, 而是浏览器. Russell 是为了浏览器在发声, 而不是代表 Web 开发者.

Russell 对现代化框架的定义主要围绕在: 技术实现上不要针对老旧的 IE, 不要使用虚拟 DOM, 性能要够好.

Russell 没有从 React 的 API 角度说明 React 的 API 设计如何对其他所谓现代化造成的影响, 比如 state 概念, hooks 概念 (当然, hooks 属于一种打补丁的概念, 但是它确实让 React 的 API 变得更好用).

作为 Web 开发者, 其实就是希望 React API 可以有一层进行隔离, 让开发者可以尽情做交互, 而不是像使用 C 一样精细化操作 DOM. 这一点上, 其实 Svelte 做的更好, 但是 Svelte 作为框架, 侵入性更强.

而 React 作为一个库, 而不是框架, 可以与现有任何 HTML 基础技术栈兼容, 并且渐进式替换.

并且, React 与 “core-js, lodash, underscore, polyfills for browsers that no longer exist, userland ECC libraries, moment.js, and a hundred other horrors” 并没有密切的关系, 使用所谓现在框架也会遇到这样的问题. 说白了, 这是开放式的浏览器生态与开发者想要避免 JS 语言历史的坑造成的矛盾, 你不能指望所有用户都用你开发的最新版渲染引擎.

React 并不可怕, 对于开发者, 其他渲染库也的确值得看:

  1. Svelte, 强制需要构建.
  2. Lit, 以前是 Polymer, Google 的维护不足让开发者跟进困难. (我们曾使用 Polymer)
  3. Vue 经过多次大版本变化, 语法经常有破坏性变化, 与 Svelte 类似但独有的语法更多. (我们曾使用 Vue 1.x, 2.x)
  4. Solid, 和 React 的语法及特点最像. (我们在部分项目中在尝试 Solid)

但是如果要用到生产环境, 我还是建议 React.

Ionic 颜色

2024年12月10日 12:00

Ionic 颜色的文档为: Ionic Colors.

本文大部分内容都来自文档.

颜色概述

Ionic 共有 9 种颜色:

  1. primary (主色, 默认为蓝色)
  2. secondary (次色, 默认为一种比较近似蓝色的颜色)
  3. tertiary (三色, 默认为另一种有点近似蓝色的颜色)
  4. success (成功色, 默认为绿色)
  5. warning (警告色, 默认为黄色)
  6. danger (危险色, 默认为红色)
  7. light (浅色, 默认为白色)
  8. medium (中色, 默认为灰色)
  9. dark (深色, 默认为黑色)

每一种颜色都包含四个属性:

  1. base (基础色)
  2. contrast (对比色, 与基础色形成鲜明对比的颜色, 一般为黑或者白)
  3. shade (阴影色, 比基础色更深一些的颜色)
  4. tint (高亮色, 比基础色更浅一些的颜色)

修改自带的颜色

Ionic 自带的颜色可以通过修改 CSS 变量来修改.

比如修改 primary 的颜色, 可以修改 ion-color-primary 的 CSS 变量.

:root {
  --ion-color-primary: #ff0000;
}

创建新的自定义颜色

首先名曲新的自定颜色的基础色, 然后使用自定义工具来创建颜色组.

:bulb: 如果不想要使用自定义工具, 也可以直接自己自定义颜色.

然后以 .ion-color-{COLOR} 为类名, 来使用新的颜色组. 如:

:root {
  --ion-color-brand-main: #69987b;
  --ion-color-brand-main-rgb: 105, 152, 123;
  --ion-color-brand-main-contrast: #000000;
  --ion-color-brand-main-contrast-rgb: 0, 0, 0;
  --ion-color-brand-main-shade: #5c866c;
  --ion-color-brand-main-tint: #78a288;
}

.ion-color-brand-main {
  --ion-color-base: var(--ion-color-brand-main);
  --ion-color-base-rgb: var(--ion-color-brand-main-rgb);
  --ion-color-contrast: var(--ion-color-brand-main-contrast);
  --ion-color-contrast-rgb: var(--ion-color-brand-main-contrast-rgb);
  --ion-color-shade: var(--ion-color-brand-main-shade);
  --ion-color-tint: var(--ion-color-brand-main-tint);
}

帮助色盲和色弱使用软件

2024年12月9日 08:00

在做 Web 设计的时候, 应该考虑色盲和色弱的人更方便使用软件. 这部分内容常被称作 accessibility, 缩写为 a11y, 中文常被称作无障碍.

色盲和色弱的基本认知

色盲和色弱是常见的视觉障碍,大约影响全球 8% 的男性和 0.5% 的女性人口。主要分为以下几类:

  • 红色盲(红色视觉缺陷)
  • 绿色盲(绿色视觉缺陷)
  • 蓝色盲(蓝色视觉缺陷)
  • 全色盲(完全无法识别颜色)

设计原则

从设计角度, 应该区分两种设计模式, 普通模式和色彩增强模式. 或者合并为一种设计模式, 支持色盲和色弱和普通用户一样正常与软件进行交互.

一般的做法是除了颜色, 要给出额外的图形信息. 比如做国内股市大盘设计时:

  1. 涨, 不仅用红色字体, 还要用向上的箭头.
  2. 跌, 不仅用绿色字体, 还要用向下的箭头.

同时, 我们也可以注意使用高对比度颜色. 比如不同颜色时, 如红色和绿色, 使用高对比度颜色, 那么色盲和色弱的人也能很容易区分.

还有增加额外的线条来增加区分度.

技术实现

从前端角度, 如果设计单独为色盲和色弱的人设计了一套 UI, 那么尽量通过额外加载 CSS 的方式进行处理.

  1. 基础
  2. 非色盲, 色弱
  3. 色盲, 色弱

普通模式加载 1 + 2, 色彩增强模式加载 1 + 3.

也可以使用普通 + 扩展的方式:

  1. 普通
  2. 色盲, 色弱

色彩增强模式加载 1, 色彩增强模式加载 1 + 2. 要确保 2 覆盖 1.

模拟与测试

对于 Web 开发来说, 可以通过 Chrome 的开发者工具, 来模拟色盲和色弱.

  1. 打开 Chrome 开发者工具.
  2. 选择更多工具.
  3. Rendering 中, 选择 Emulate vision deficiencies.
  4. 可以选择一些情况进行模拟.

规则的执行比规则设计是否精妙更重要

2024年12月5日 08:00

在管理实践中, 我们经常会遇到这样的困惑: 为什么精心设计的规则在实际执行中收效不佳? 本文将探讨规则设计与执行的关系.

无论是国家治理还是公司管理, 都可以总结为下面的几点:

  1. 设计规则. (立法, 司法)
  2. 确保规则被执行. (执法)
  3. 按照规则进行. (守法)

针对日常工作存在的问题, 我总想通过制定规则, 然后通过执行这些规则来解决问题.

但我太执着于规则的设计, 而忽略了规则的执行.

有的时候规则没有产生预期的效果, 并不是规则设计的不够精妙, 而是规则执行的不够彻底.

在确保规则被执行的前提下, 再去完善规则才能让规则发挥最大的作用.

如果有令不行, 有禁不止, 那么规则设计的再精妙也是无用.

GitHub 投票设计

2023年5月1日 08:00

GitHub 投票

GitHub 的投票功能位于 Discussions 中, 有一个分类叫作 Polls.

Polls 有基础的投票功能, 但不是表单那种复杂设计.

如果想要自定义分类也可以, 只需要将分类的 Discussion Format 设置为 Poll 即可. 但有两个限制:

  1. 已经设置为 Poll 的分类不能修改.
  2. 其他分类不能改为 Poll 分类.

所以基本只能在创建分类的时候就选好 Poll 格式.

GitHub 的投票相比钉钉/飞书群投票功能区别

  1. GitHub 仅支持不投票即可查看结果功能.
  2. GitHub 不支持不投票则不可查看结果功能.
  3. GitHub 仅支持匿名投票.
  4. GitHub 不支持查看投票者名单功能.
  5. GitHub 不支持设置可投票者名单功能.

扩展

2022 年 4 月发布投票功能. https://github.blog/changelog/2022-04-12-discussions-polls/

也有其他人有上文说到的 “支持查看投票者名单功能” 的需求. https://github.com/orgs/community/discussions/5650

在 Deno 中实现 HTTP 返回 body 的 Brotli 压缩

2022年2月23日 08:00

:warning: 本文是 2022 年 2 月 23 日写的, 现在 Deno 已经有了变动, 所以本文在部分地方可能已经过时.

在 9 个月之前, 我们在项目中创建了这则 issue, 今天, 伴随着 Deno 最近标准库的变动, 我们对此进行更加系统地说明.

Why & What

之前, 我们的 Web 项目对 HTTP 返回 body 实现了 deflate 的压缩算法, 但使用的是 JS, 还是不够快. 我们考虑支持对此进行优化.

我们知道对于大多数浏览器来说, 都会发送这样的请求头 Accept-Encoding: gzip, deflate, br.

其中 br 就是我们暂时不支持的 br 压缩, 即 Brotli 压缩算法.

从发展来看, br 是更适合 HTTP 的压缩算法, 现代浏览器也都支持了.

https://hacks.mozilla.org/2015/11/better-than-gzip-compression-with-brotli/

在 Deno 项目中实现 br

但目前 Deno 仍未有对此的支持计划. (有 issue, 但还没计划去做)

在 Node.js 中, 有标准库 zlab 去实现该压缩算法. https://nodejs.org/api/zlib.html#zlib_class_zlib_brotlicompress

但在 Deno 中, 官方不支持.

在 npm 中有这样的包 https://www.npmjs.com/package/brotli 来实现 br 算法压缩. 利用了 Emscripten(C++) 去实现.

npm 的包是不能在 Deno 上使用的. 在调用其他方式上, 是通过 WASM.

虽然能看到 WASM 本体 https://cdn.jsdelivr.net/npm/brotli@1.3.2/build/mem.js 但是现在还不能直接在 Deno 项目中用, 需要对包引用进行变动.

然后尝试在 Deno 社区中找相关解决方案, 就是 https://github.com/denosaurs/deno_brotli.

正如所有 Deno 项目一样, deno_brotli 的使用非常简单, 只需要 import { compress } from 'https://deno.land/x/brotli@v0.1.4/mod.ts'; 即可.

在 Deno Web 项目中实施返回 body 的压缩

假设我们已经有了要返回的 body 和 headers, 并且知道了请求方支持的压缩方式 acceptEncoding, 那么我们可以简单进行如下操作:

if (body !== null && body.length > 200) {
  if (acceptEncoding.includes('br')) {
    body = compress(new TextEncoder().encode(body));
    headers.set('content-encoding', 'br');
    headers.set('content-length', body.length.toString());
  }
}

deno_brotli 是什么

其实 deno_brotli 就做了一件事情: src/lib.rs

然后就是通过命令编译为 wasm.js

其中, 使用的 https://github.com/rustwasm/wasm-bindgen 项目还是挺值得我们学习一下的, 可以大幅扩展 JS 的能力, 就像本次利用了 https://github.com/dropbox/rust-brotli 这个库一样.

使用多设备开发时的技巧

2020年6月9日 08:00

多设备开发时, 代码如何同步, 常用偏好如何同步, 怎么方便地进行切换. 这是个课题.

我大概有两种思路:

  1. 远程开发机.
  2. 编辑器同步设置.

使用远程开发机的做法是最彻底的, 但同时也是存在弊端的. 比如前端开发时使用 8080 端口, 但如果多人使用开发机或者多台开发机所在同一网络, 则会出现冲突.

编辑器同步设置则需要再对多个开发目录进行额外同步, 比如 .ssh/ 和项目 Git 目录.

以下均以 VS Code 为例.

远程开发机

使用 VS Code 扩展 Remote - SSH 可以更加方便地在远程开发机上进行开发.

编辑器同步设置

看到一篇帖子在问如何在多台设备上同步 VS Code 的设置. 我正有此痛点.

在帖子中看到两种做法:

  1. 官方自带, 但目前仅限 VS Code Insiders 测试版.
  2. 使用扩展.

基于对微软的信任, 有官方的自然用官方的.

VS Code Insiders 的图标是青色的, 可以与 VS Code 同时存在.

Settings Sync 功能使用起来非常简单, 登录然后选择同步就好了.

这里说一下登录, 和 Live 功能类似, 但以前只有微软账号, 现在 (可能和收购有关系?) 还可以选 GitHub 账号. 如果同时有两个平台的账号, 建议还是选择 GitHub, 因为在使用中发现如果登录失败, 当使用 GitHub 时, 可以通过 code 再次进行登录尝试, 程序员更友好一些吧.

Node

2020年5月22日 08:00

Node.js事件

什么是事件轮询

  • 事件循环是 Node.js 处理非阻塞 I/O 操作的机制——尽管 JavaScript 是单线程处理的——当有可能的时候,它们会把操作转移到系统内核中去。

事件轮询机制解析

  • 当 Node.js 启动后,它会初始化事件轮询;处理已提供的输入脚本(或丢入 REPL,本文不涉及到),它可能会调用一些异步的 API、调度定时器,或者调用 process.nextTick(),然后开始处理事件循环。
┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

阶段概述

    1. 定时器:本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。
    1. 待定回调:执行延迟到下一个循环迭代的 I/O 回调。
    1. idle, prepare:仅系统内部使用。
    1. 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞。
    1. 检测:setImmediate() 回调函数在这里执行。
    1. 关闭的回调函数:一些关闭的回调函数,如:socket.on(‘close’, …)。
  • 在每次运行的事件循环之间,Node.js 检查它是否在等待任何异步 I/O 或计时器,如果没有的话,则完全关闭。

引用链接: https://nodejs.org/zh-cn/docs/guides/event-loop-timers-and-nexttick/

Node Npm Cnpm Yarn Pnpm

2020年5月18日 08:00

node依赖管理

  • Node的依赖管理工具
    1. npm
    1. cnpm
    1. yarn
    1. pnpm

npm

    1. 使用一个名为package.json的文件,用户可以通过npm install –save命令把项目里所有的依赖项保存在这个文件里
    1. npm安装插件是从国外服务器下载,受网络影响大,可能出现异常

cnpm

    1. cnpm跟npm用法完全一致, 服务器在国内, 访问速度很快

yarn

    1. yarn是经过重新设计的崭新的npm客户端,它能让开发人员并行处理所有必须的操作,并添加了一些其他改进
    1. 运行速度得到了显著的提升,整个安装时间也变得更少
    1. 像npm一样,yarn使用本地缓存。与npm不同的是,yarn无需互联网连接就能安装本地缓存的依赖项,它提供了离线模式。
    1. 允许合并项目中使用到的所有的包的许可证

pnpm

    1. pnpm运行起来非常的快,超过了npm和yarn
    1. pnpm采用了一种巧妙的方法,利用硬链接和符号链接来避免复制所有本地缓存源文件,这是yarn的最大的性能弱点之一
    1. pnpm继承了yarn的所有优点,包括离线模式和确定性安装

引用地址: https://blog.csdn.net/qq_32614411/article/details/80894605

Headless Brower

2020年5月11日 08:00

Headless Brower

Headless Brower 直译为中文是无头浏览器。其中的无头是指没有图形界面的意思。也就是通过代码来控制与浏览器的交互。比如捕获页面内容加载完成事件,执行按钮的点击事件,执行键盘输入,表单提交等。

Headless Chrome

Chrome 59 版本开始,Chrome 浏览器加入了 Headless 运行模式。除了没有图形界面以外,在 Headless 模式下可以实现 Chrome 浏览器的所有功能。

此外,Chrome 团队开发了 Chrome 开发工具协议,简称 CDP(Chrome DevTools Protocol)。该协议提供了很多有用的功能 API,比如在 DOM,调试器和网络方面等。Chrome 浏览器中的开发者工具正是使用了该协议实现其功能。

Chrome 开发工具协议使得 Headless Chrome 的功能更加强大。

Headless Chrome 库

一些第三方代码库提供了更加方便的使用 Headless Chrome 功能的方法。

Chromedp 是使用 Golang 语言实现的一种更加简单快速的方式驱动支持 Chrome DevTools 协议浏览器的方式,无需外部依赖。

Selenium 是用于测试 Web 应用程序用户界面的常用框架。同时也支持所有基于 Web 的管理任务自动化。支持的语言有 Java,Python,C#,Ruby,Javascript 和 Kotlin。

puppeteer 是使用 Node 语言实现的 Web 应用自动化测试工具。是 Google Chrome 团队官方的 Headless Chrome 工具。

Headless Chrome 库应用场景

  • 页面自动化测试
    可以通过 Headless Chrome 直接测试页面中的内容和交互。而不仅限于代码测试。
  • 爬虫
    对于某些不会直接显示在 HTML 节点中的内容,例如页面成功加载后再通过 AJAX 与后端服务器请求的内容或单页应用,可以使用 Headless Chrome 来获取。
  • 保存页面副本
    可以通过代码自动将需要的页面保存为图片或 PDF 文件

总之,Chrome 浏览器能够实现的功能在 Headless 模式中都可以实现。加入程序使得我们可以实现更多更强大的功能。

参考

Cloudwatch

2020年5月8日 08:00

什么是CloudWatch

Amazon CloudWatch 实时监控您的 Amazon Web Services (AWS) 资源以及您在 AWS 中运行的应用程序。 可以使用 CloudWatch 收集和跟踪指标,这些指标是可衡量的相关资源和应用程序的变量。

CloudWatch的四大功能

  • 指标:从AWS的服务中收集数据放到metrics,然后通过available statistics显示到控制台上
  • 警报:通过对指标的判断,可以发出邮件,或执行auto scaling
  • 日志:会将lambda/RDS等执行的日志放到log中,方便处理
  • 对事件处理的功能:通过EC2实例或其他服务触发,调用到其他的服务,比如调用lambda

EC2的监控指标

  • 可以查看CPU,磁盘,网络等指标,但是没有内存的指标,AWS承诺不会动客户的任何数据, 也不会在EC2实例上安装任何的插件, 客户可以在市场上找一些流行的性能监控软件取到EC2的内存, 然后调用cloudwatch的API然后展示到如下监控的指标列表中。

EC2创建警报

  • 可根据各类指标创建警报

创建事件

  • 可以设置特定的时间或者时间区间,调用一次lamda函数

Awesome

2020年5月6日 08:00

awesome系列github上超有名的Topic

大部分有一定知名度的领域,都有着自己的awesome-xxx项目

awesome Topic简要的事实描述

1、目前awesome系列包含了3325个各类仓库
2、Star数最多的awesome的主仓库,stars>132k
3、Topic中stars超过10k的有超过60个

要了解这个系列,可以直接从awesome项目开始(indresorhus/awesome)项目包含平台类、编程语言、前端开发、后端开发、计算机科学、大数据、理论、书籍、编辑器、游戏开发、开发环境、娱乐、数据库、媒体、学习资料与方法、安全、内容管理系统、硬件、创业与商务、工作方法、网络、分散系统、高等教育、事件、测试等相关集合。

这些集合包括了相关领域的书籍、课程、论文、软件、数据集、教程、博客等。以python为例,awesome-python(star:82.1k),仓库收纳了Web框架、网络爬虫、内容管理系统、计算机视觉、密码学、数据分析、数据可视化、深度学习、游戏开发、机器学习、自然语言处理、内容推荐系统、机器人技术、代码日志分析等内容。

目录对收录的资源做了简要的介绍,点击链接就可以直达资料页。

以下是挑选的一些目前10k+的获取对我们的工作学习有用的热门awesome仓库:

  • sindresorhus/awesome: Github stars 132k (各种有趣话题的精彩列表)
  • vinta/awesome-python: Github stars 82.1k (一份精选的优秀Python框架列表)
  • avelino/awesome-go: Github stars 54.1k (一份精选的优秀Go框架列表)
  • sindresorhus/awesome-nodejs: Github stars 35.6k (有趣的Node.js包和资源)
  • dypsilon/frontend-dev-bookmarks: Github stars 27.1k (前端web开发人员的资源集合。)
  • ziadoz/awesome-php: Github stars 23.5k (一份精选的PHP库列表)
  • brillout/awesome-react-components: Github stars 22.4k (React组件和库的管理列表。)
  • veggiemonk/awesome-docker: Github stars 17.7k (精选的docker资源和项目清单)
  • viatsko/awesome-vscode: Github stars 17.1k (一个令人愉快的VS代码包和资源的列表)
  • AllThingsSmitty/css-protips: Github stars 14.4k (一个帮助你掌握CSS技巧的技巧集)
  • tmrts/go-patterns: Github stars 12.6k (Go语言惯用设计和应用程序模式的集合)
  • gztchan/awesome-design: Github stars 12k (设计资源)
  • xgrommx/awesome-redux: Github stars 11.7k (很赞的Redux示例和中间产品列表)

Pm Em Rem

2020年4月29日 08:00

在css中单位长度用的最多的是px、em、rem,这三个的区别是:

  px是固定的像素,一旦设置了就无法因为适应页面大小而改变。

  em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定死了的,更适用于响应式布局。 对于em和rem的区别一句话概括:em相对于父元素,rem相对于根元素 rem中的r意思是root(根),这也就不难理解了

em

  • 子元素字体大小的em是相对于父元素字体大小

  • 元素的width/height/padding/margin用em的话是相对于该元素的font-size ```

我是父元素div

我是子元素p 我是孙元素span

div { font-size: 40px; width: 10em; /* 400px / height: 10em; / 400px / border: solid 1px black; } p { font-size: 0.5em; / 20px / width: 10em; / 200px / height: 10em; / 200px / border: solid 1px red; } span { font-size: 0.5em; / chrome有最小字体12px的限制所以这里为 12px / width: 10em; / 120px / height: 10em; / 120px */ }


### rem
rem是全部的长度都相对于根元素,根元素是谁?<html>元素。通常做法是给html元素设置一个字体大小,然后其他元素的长度单位就为rem。

html { font-size: 10px; } div { font-size: 4rem; /* 40px / width: 30rem; / 300px / height: 30rem; / 300px / border: solid 1px black; } p { font-size: 2rem; / 20px / width: 15rem; / 150px / height: 15rem; / 150px / } span { font-size: 1.5rem; / 15px / width: 10rem; / 100px / height: 10rem; / 100px */ } ```

❌
❌