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

原文: https://blog.cloudflare.com/unpacking-cloudflare-workers-cpu-performance-benchmarks/ 原文主要讲述了 Cloudflare Workers 和 Vercel 在 CPU 性能方面的一些对比, 在应用上的重点是 React SSR 类应用的 TTFB 测试. 其中我认为的一些关键点是: 函数计算的调度问题 (非 CPU 计算消耗). Node.js 对 V8 调参导致的性能问题. 代码中处理 buffer 不当导致的内存占用及后续 GC 的问题. Node.js 的非 Web 标准化问题, 比如 Streams API. Cloudflare Workers 团队在解决自己问题的过程中如果发现了生态问题, 甚至竟品问题, 也期望一并解决. 我们的核心业务均由函数计算承担, 在此处有许多经验. 函数计算中的几大时间消耗为: 调度时间 (可能) 冷启动时间 执行时间 (被计算为 CPU 消耗) 一般来说, “执行时间” 与函数计算无关. 函数计算需要重点考虑的, 是 “调度时间” 和 “冷启动时间”. 作为用户, 一些配置会影响到调度时间, 比如使用什么操作系统, 是否要接入 VPC 等. 想要优化冷启动时间, 则应该将重点放在 “架构” 上. 一般来说, 解释型语言的冷启动时间会小很多. 比如函数计算一般使用 Python, JavaScript, 而不使用 Java. 另外一种优化就是 “预热”, 可以理解为提前启动. 但是预热是有成本开销的, 并且我认为预热是有悖于函数计算模式的. 我更倾向于减少冷启动时间, 而不是预热. Cloudflare Workers 针对调度问题的优化, 是所有用户乐于看到的. 加量不加价, 并且默认生效, 用户无需任何额外配置. Node.js 的非 Web 标准化问题, 就是我们几年前选型 Deno, 而非 Node.js 的关键原因. 即便我们不是全栈团队, 也希望在 JS 领域, 技术栈尽量统一, 减少不必要的消耗. 最后, 看到问题就想要去解决, 无论这个问题是否影响到自身利益, 这不仅是工程师应该有的素质, 也是每一个人应该有的素质. 就像走路时如果看到了脚边的垃圾, 可以顺手捡起来扔到垃圾箱中. 不是鼓励大家无偿奉献, 而是举手之劳, 何乐而不为? 每个人多付出 1%, 就会让整个世界进步不只 100%.

2025/10/16
articleCard.readMore

Deno Fresh 2.x 支持 Vite

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 是支持在编译时处理动态路由并且打包的, 也支持代码分割. 在官方文章中, 主要介绍了下面几个功能: 借助 Vite 的 岛内热加载, 而不是全页热加载. 借助 Vite 的 服务器代码打包, 加快启动时间. 借助 Vite 的 React 别名. 回归的 Head 组件 Fresh 2.0 正式进入 beta, 不再会有重大变动. 现在就可以尝试了.

2025/9/3
articleCard.readMore

TypeScript 使用 Go 进行了重构

我在 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 语言进行编译器移植的原因主要包括: 可维护性: Go 语言拥有高效且易于理解的垃圾收集器, 简单易学的语法以及良好的 开发者生态系统, 使得维护大型代码库更加容易 性能优势: Go 编译器的多方面优化使其非常适合构建编译器这类程序, 并且与 JavaScript 版本相比, 能够显著提高编译速度 跨平台能力: Go 的原生编译特性让 TypeScript 编译器能够轻松构建为适用于 各种操作系统的单一二进制文件 开发效率: 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) 上. 相关链接 A 10x Faster TypeScript GitHub 仓库: typescript-go

2025/3/13
articleCard.readMore

JS 中的链式调用

数组中的链式调用 const numbers = [1, 2, 3, 4, 5]; const result = numbers .filter(n => n % 2 === 0) // 过滤偶数 .map(n => n * 2) // 每个数乘以2 .reduce((sum, n) => sum + n, 0); // 求和 但是仅限于数组, 如果想要在其他对象上实现链式调用, 就需要自定义方法. 多变量链式调用 为了可以对任何数据使用自定义方法, 我们可以这样做: function add(x, y) { return x + y; } function multiply(x, y) { return x * y; } let num = 0; let num2 = add(num, 5); let num3 = multiply(num2, 2); let num4 = add(num3, 3); console.log(num4); // 13 这种做法的缺点是额外增加了许多变量, 为了这些变量要进行许多不必要的命名. 多函数嵌套链式调用 为了避免不必要的命名, 我们可以直接调用: const result = add(multiply(add(0, 5), 2), 3); console.log(result); // 13 可是这样做后, 代码的可读性很差. 对象方法链式调用 class Calculator { constructor() { this.value = 0; } add(n) { this.value += n; return this; } multiply(n) { this.value *= n; return this; } getValue() { return this.value; } } const calc = new Calculator(); const result = calc .add(5) .multiply(2) .add(3) .getValue(); // 13 但是需要额外新增对象, 并且许多时候函数作为方法并不合适. Promise 中的链式调用 为了解决上述问题, 我们可以使用 Promise 的链式调用: const result = await Promise.resolve(0) .then(x => add(x, 5)) .then(x => multiply(x, 2)) .then(x => add(x, 3)); console.log(result); // 13 并且这种做法可以仅仅使用匿名函数, 不使用函数, 在一些小变动的时候很方便: const result = await Promise.resolve(0) .then(x => x + 5) .then(x => x * 2) .then(x => x + 3); console.log(result); // 13 目前这是我最常用的方法. 但是缺点是强制将代码转为了异步. JS Pipe Operator (管道操作符) 提案 https://github.com/tc39/proposal-pipeline-operator 参考了几种语言的语法: Hack F# 另外, 许多其他语言也有类似语法, 比如 Elixir.

2025/1/14
articleCard.readMore

Flutter Web 开发注意事项

注意事项 为了更好支持 web WebAssembly, 建议 Flutter 版本 >= 3.24. 可以使用 https://flutterweb-wasm.web.app/ 测试 Flutter Web 的性能. 目前默认使用 canvaskit 渲染, 性能较差. 如果使用 wasm 构建, 则使用 Skwasm 渲染. Safari 17.5, Firefox 133 目前渲染目前会回退到 canvaskit, 性能较差. 编译参数 flutter run 和 flutter build web 命令的参数: --wasm 使用 wasm 的方式构建 如 flutter run -d chrome --wasm 如 flutter build web --wasm 包 参考 Flutter 文档: https://docs.flutter.dev/platform-integration/web/renderers, 开发时不建议使用的包有: dart:html, 建议使用 package:web 替代. 以使用 WebAssembly 方式构建. dart:js, 建议使用 dart:js_interop 替代. 以使用 WebAssembly 方式构建. dart:js_util, 建议使用 dart:js_interop 替代. 以使用 WebAssembly 方式构建. package:js, 建议使用 dart:js_interop 替代. 以使用 WebAssembly 方式构建.

2024/12/31
articleCard.readMore

软件架构与实验艺术

:bulb: 原文链接: https://www.infoq.com/articles/architecture-experimentation/ 在软件架构领域, 我们经常会做出许多决策. 有些决策会带来积极的影响, 而有些则会产生消极的后果. 在做出这些决策时, 我们往往会陷入两难境地: 我们希望做出正确的决策 我们无法预知未来 这就像是在玩一个概率游戏. 我们可以通过研究, 分析和经验来提高做出好决策的概率, 但我们永远无法完全确定某个决策就一定是正确的. 通过实验来验证决策 在这种情况下, 唯一合理的方法就是通过实验来验证我们的决策. 这意味着: 承认我们可能会犯错 设计实验来测试我们的假设 收集数据来验证决策的效果 准备好在需要时调整或改变方向 让我给您举个例子. 假设您正在开发一个新的在线零售平台, 需要决定使用哪种数据库技术. 您可能会考虑: 关系型数据库(如 PostgreSQL) NoSQL 解决方案(如 MongoDB) 分布式数据存储系统 与其仅仅基于理论讨论做出选择, 不如设计一些实验来测试每种选项在您的具体场景中的表现. 最小可行架构(MVA) 最小可行架构(MVA)是一个重要概念, 它强调: 从最简单的可工作方案开始 通过实验逐步验证和改进 在实际使用中收集反馈 根据反馈调整架构决策 MVA 与最小可行产品(MVP)的理念相似, 但关注点是技术架构而不是业务功能. 实验的重要性 在软件开发中, 每个产品发布实际上都是一系列实验的集合. 这些实验不仅关于产品功能, 还包括: 技术可行性 - 选择的技术方案是否真的能够实现预期目标 可维护性 - 系统是否容易维护和更新 可扩展性 - 系统能否应对增长需求 运营成本 - 解决方案在财务上是否可持续 实验设计的关键要素 好的架构实验应该包含以下要素: 明确的假设 清晰陈述我们认为会发生什么 为什么我们认为会这样 这些假设基于什么依据 可测量的目标 具体的性能指标 明确的成功标准 可量化的结果 实验方法 如何进行测试 需要收集什么数据 如何收集这些数据 风险控制 失败后的回退方案 对系统其他部分的影响评估 如何隔离实验的影响范围 时间框架 实验持续时间 关键时间节点 评估周期 实验的实际案例 让我们看一个具体的例子: 假设一个团队正在考虑将单体应用迁移到微服务架构。他们可以这样设计实验: 实验名称:核心功能微服务迁移测试 假设: 将订单处理模块拆分为独立微服务将提高系统扩展性 服务间通信不会显著影响性能 测试方法: 选择一个非关键时段 将订单处理模块拆分为独立服务 部署到生产环境的隔离区域 使用影子流量进行测试 成功标准: 响应时间不超过现有系统的 120% 系统资源使用率保持在可接受范围 服务间通信延迟低于 50ms 回退计划: 保留原有系统运行 准备快速切换回原架构的脚本 预设故障转移机制 实验的陷阱 在进行架构实验时,需要注意避免以下常见陷阱: 范围过大 试图一次性解决太多问题 实验周期过长 难以确定具体问题的根源 指标模糊 成功标准不够具体 缺乏量化指标 难以做出客观评判 忽视成本 未考虑实验失败的代价 忽视长期维护成本 低估迁移成本 实验驱动的架构演进 渐进式变更 在进行架构演进时,采用渐进式的变更策略非常重要: 小步快跑 将大型变更分解成小的、可管理的步骤 每个步骤都可以独立验证 降低每次变更的风险 持续验证 在每个阶段收集反馈 及时发现问题并调整 建立度量标准来评估进展 保持可逆性 确保每个变更都是可回退的 维护多个系统版本的能力 准备应急方案 实验的生命周期 一个完整的架构实验生命周期包括: 规划阶段 定义实验目标 设计实验方案 确定评估标准 准备阶段 搭建测试环境 准备监控工具 建立基准数据 执行阶段 实施变更 收集数据 监控系统 评估阶段 分析结果 总结经验 决定下一步 调整阶段 根据结果优化 扩大或缩小范围 准备下一轮实验 实验文化的建立 要在团队中建立良好的实验文化: 鼓励创新 接受失败作为学习的一部分 奖励大胆尝试 分享经验教训 数据驱动 基于事实做决策 建立度量体系 重视客观反馈 持续学习 定期回顾实验结果 记录和分享知识 调整实验方法 实际案例研究 让我们看一个更详细的案例: 案例:缓存层改造实验 背景: 现有系统使用单机缓存 随着用户增长,出现性能瓶颈 考虑迁移到分布式缓存 实验设计: 第一阶段:小规模测试 选择非核心业务模块 部署分布式缓存集群 监控性能和稳定性 第二阶段:负载测试 模拟生产环境负载 测试故障转移 评估运维复杂度 第三阶段:灰度发布 逐步迁移业务模块 观察系统表现 收集用户反馈 评估指标: 缓存命中率 响应时间 系统资源使用 运维成本 长期架构演进 平衡短期与长期目标 在进行架构实验时,需要考虑: 短期收益 立即可见的性能提升 快速解决当前问题 用户直接感受的改进 长期影响 技术债务的累积 维护成本的变化 未来的扩展性 权衡因素 开发速度 vs 代码质量 创新 vs 稳定性 灵活性 vs 复杂度 持续改进的策略 为确保架构能持续演进: 建立反馈循环 监控系统性能 收集用户反馈 分析运营数据 定期评估 架构审查会议 性能基准测试 技术栈评估 适应性调整 根据业务需求调整 采纳新技术 淘汰过时组件 常见陷阱和解决方案 在长期架构演进中常见的问题: 过度工程 问题:构建超出实际需求的复杂系统 解决:坚持”足够好”原则,循序渐进 决策惯性 问题:因为历史原因继续使用次优方案 解决:定期重新评估决策,保持开放心态 忽视维护性 问题:只关注功能实现,忽视后期维护 解决:将可维护性作为架构决策的关键指标 文档和知识管理 保持良好的文档习惯: 决策记录 记录重要决策的原因 记录被否决的方案 保存相关讨论内容 实验日志 详细的实验过程 数据收集方法 结果分析 经验教训 成功和失败的案例 意外情况的处理 改进建议 团队协作 有效的团队协作对实验成功至关重要: 沟通机制 定期架构讨论会 技术评审流程 知识分享会议 角色分工 实验负责人 监控人员 评估团队 决策流程 提案机制 评审流程 实施审批 结论与展望 实验驱动的架构方法总结 成功的架构实验方法建立在以下基础之上: 实验思维 承认不确定性的存在 愿意通过实验来验证假设 对失败保持开放态度 系统方法 明确的实验流程 可靠的数据收集 客观的评估标准 完善的反馈机制 持续改进 不断优化实验方法 积累经验教训 调整决策流程 未来趋势 架构实验在未来可能的发展方向: 自动化实验 自动化测试和部署 AI 辅助决策 智能监控和分析 混沌工程 主动故障注入 弹性测试 系统边界探索 实验工具链 集成的实验平台 可视化分析工具 协作决策系统 最佳实践建议 给架构师和开发团队的建议: 开始时要小 从小规模实验开始 逐步增加复杂度 积累经验和信心 保持警惕 持续监控系统 注意早期警告信号 及时调整方向 分享知识 记录和分享经验 建立知识库 促进团队学习 结束语 架构实验不是一次性的活动,而是持续改进的过程。成功的关键在于: 建立正确的实验文化 采用系统的方法论 保持学习和适应的能力 重视团队协作和知识共享 通过实验驱动的方法,我们可以: 降低架构决策的风险 提高系统的可靠性 促进团队的成长 推动技术的创新 最终,架构实验的目标是帮助我们构建更好的系统,为用户创造更大的价值。 参考资料 相关书籍和文章推荐 实用工具和框架 案例研究和最佳实践 社区资源和讨论组 这就是全文的完整翻译. 这篇文章深入探讨了软件架构中实验的重要性, 以及如何通过系统化的方法来进行架构实验和演进. 希望这个翻译对您有帮助!

2024/12/25
articleCard.readMore

OpenAI 12 Days 总结

中文版本 发布会 OpenAI 最新办了一场 12 天 “发布会”: https://openai.com/12-days/ 国内文章: https://www.infoq.cn/article/WXPMviOWQ1LNZhqZC5ZE 总结这几天的内容, 核心为: ChatGPT Pro 服务, 200 美元/月 (Day 1) 正式发布 o1 模型 (Day 1, 9) 正式发布 Sora 模型 (Day 3) 技术预览 (微调与 o3 模型) (Day 2, 12) 更多应用层面的更新 (创作者助手, 苹果集成, 会话整理, 多媒体信息, 搜索, 电话版 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: ChatGPT Pro service at $200/month (Day 1) Official release of o1 model (Day 1, 9) Official release of Sora model (Day 3) Technical previews (fine-tuning and o3 model) (Day 2, 12) 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.

2024/12/22
articleCard.readMore

Deno 使用实践与总结

中文版本 Deno 中的依赖管理 直接使用 import 进行相对路径的文件引用. 直接使用 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 引用 npm 包. 引用 jsr 包. (仅限公共包). jsr.io 包仓库 jsr.io 是 Deno 官方团队开发维护的一个包仓库, 可以同时发布为 Deno 和 Node.js 的包. 如果没有 jsr.io, 如果一个包想要同时支持 Deno 和 Node.js, 那么需要维护两套代码. 如果不想维护两套代码, 则可以构建时魔改代码, 但会受到许多约束: 转为 Node.js 包的时候移除 .ts 后缀名. 无法添加 deno 依赖. 无法添加 Node.js 依赖. jsr.io 的包可以同时支持 Deno 和 Node.js, 解决了上述痛点. 但是 jsr.io 有两大问题: jsr.io 不支持 HTTP 绝对路径的文件引用. 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 的包. 但是这种支持仍然有限: localAddress 参数没有效果. https://github.com/denoland/deno/issues/24153 更多兼容问题见 issue 列表 Deno 支持不完善的 Node.js 功能 Deno 暂不支持的 Node.js 功能 原生 Deno API 目前 Deno 提供的 API 仍有限, 比如有下面的问题: 网络请求时不支持选择网卡. https://github.com/denoland/deno/issues/27376 不支持 brotli 压缩. (但通过 Node.js 兼容包可实现) English Version Dependency Management in Deno Direct file imports using relative paths. 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 Importing npm packages. 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: Removing .ts extensions when converting to Node.js packages. Cannot add Deno dependencies. 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: jsr.io doesn’t support HTTP absolute path imports. 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: localAddress parameter has no effect. https://github.com/denoland/deno/issues/24153 More compatibility issues in the issue list Partially supported Node.js features in Deno Currently unsupported Node.js features in Deno Deno API Currently, Deno’s API offerings are still limited, with issues such as: No support for network interface selection in network requests. https://github.com/denoland/deno/issues/27376 No support for brotli compression. (though achievable through Node.js compatibility packages)

2024/12/19
articleCard.readMore

Cursor 使用问题

中文版本 对于中国国内开发者来说, Cursor 尤其好用. 因为通过 Cursor 可以使用多种大语言模型, 并且可以避免自己直接订阅导致封号等风险. 但是作为一个文本编辑器, 虽然集成自 VS Code, 但 Cursor 仍有许多基础功能没做好: 同一用户多设备的配置数据同步. 第三方软件集成 (如 Fork). macOS 下将 Find 文件或文件夹拖拽到 icon 打开 (系统集成). 许多开发者都有多台开发设备, 大多数开发者希望在多台设备上拥有较为一致的开发体验. VS Code 在这方面做的就很好. 但是 Cursor 无法在统一用户的多台设备上进行配置数据的同步, 扩展也需要分别安装. 在第三方软件集成度上, Cursor 也有问题. 以 Fork 为例, 虽然不知道问题是在 Fork 还是在 Cursor 上, 但用户体验上的确不够, 还不如 Zed. 以前 Open in 都不支持 Cursor, 现在 Reveal Line 还是不支持. 在 Mac 上不支持将文件夹拖转到 icon 上打开. (以前连文件拖拽打开都不支持) Cursor 还需要把编辑器本身的工作做好啊. English Version For developers in China, Cursor is particularly useful because it provides access to various large language models while avoiding the risks of direct subscription that might lead to account suspension. However, as a text editor, despite being based on VS Code, Cursor still lacks several basic features: Configuration data synchronization across multiple devices for the same user. Third-party software integration (such as Fork). Opening files/folders by dragging them onto the icon on macOS (system integration). Many developers work with multiple devices, and most prefer to have a consistent development experience across all their devices. VS Code handles this well. However, Cursor cannot synchronize configuration data across multiple devices for the same user, and extensions need to be installed separately on each device. Regarding third-party software integration, Cursor has issues. Taking Fork as an example, regardless of whether the problem lies with Fork or Cursor, the user experience is inadequate and inferior to Zed. Previously, “Open in” didn’t support Cursor, and “Reveal Line” still doesn’t work. On Mac, it doesn’t support opening folders by dragging them onto the icon. (Previously, it didn’t even support opening files by dragging) Cursor needs to improve its core editor functionality.

2024/12/12
articleCard.readMore

谈 Alex Russell 谈 React

我看了部分 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? 简单来说有三点: React 可以实现我们的需求. React 提供了一套简单的原则, 状态数据 + JSX. React 简单易懂. 在工程上有足够的优势. 生态好. 因为 React 有先发优势, 可能也因为 React 在其他方面有优势. 并不是因为: “Facebook 用了 React, 所以我们用肯定没问题.” React 是 Facebook 的产物, 但是 React 之所以成为一个开源项目, 是因为 React 解决的是一个通用且朴素的问题. “React 是行业标准.” 我们也不认为 React 是标准, 但不可否认 React 对其他许多流行库造成了深远的影响. “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 并不可怕, 对于开发者, 其他渲染库也的确值得看: Svelte, 强制需要构建. Lit, 以前是 Polymer, Google 的维护不足让开发者跟进困难. (我们曾使用 Polymer) Vue 经过多次大版本变化, 语法经常有破坏性变化, 与 Svelte 类似但独有的语法更多. (我们曾使用 Vue 1.x, 2.x) Solid, 和 React 的语法及特点最像. (我们在部分项目中在尝试 Solid) … 但是如果要用到生产环境, 我还是建议 React.

2024/12/11
articleCard.readMore

Ionic 颜色

Ionic 颜色的文档为: Ionic Colors. 本文大部分内容都来自文档. 颜色概述 Ionic 共有 9 种颜色: primary (主色, 默认为蓝色) secondary (次色, 默认为一种比较近似蓝色的颜色) tertiary (三色, 默认为另一种有点近似蓝色的颜色) success (成功色, 默认为绿色) warning (警告色, 默认为黄色) danger (危险色, 默认为红色) light (浅色, 默认为白色) medium (中色, 默认为灰色) dark (深色, 默认为黑色) 每一种颜色都包含四个属性: base (基础色) contrast (对比色, 与基础色形成鲜明对比的颜色, 一般为黑或者白) shade (阴影色, 比基础色更深一些的颜色) 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/10
articleCard.readMore

帮助色盲和色弱使用软件

在做 Web 设计的时候, 应该考虑色盲和色弱的人更方便使用软件. 这部分内容常被称作 accessibility, 缩写为 a11y, 中文常被称作无障碍. 色盲和色弱的基本认知 色盲和色弱是常见的视觉障碍,大约影响全球 8% 的男性和 0.5% 的女性人口。主要分为以下几类: 红色盲(红色视觉缺陷) 绿色盲(绿色视觉缺陷) 蓝色盲(蓝色视觉缺陷) 全色盲(完全无法识别颜色) 设计原则 从设计角度, 应该区分两种设计模式, 普通模式和色彩增强模式. 或者合并为一种设计模式, 支持色盲和色弱和普通用户一样正常与软件进行交互. 一般的做法是除了颜色, 要给出额外的图形信息. 比如做国内股市大盘设计时: 涨, 不仅用红色字体, 还要用向上的箭头. 跌, 不仅用绿色字体, 还要用向下的箭头. 同时, 我们也可以注意使用高对比度颜色. 比如不同颜色时, 如红色和绿色, 使用高对比度颜色, 那么色盲和色弱的人也能很容易区分. 还有增加额外的线条来增加区分度. 技术实现 从前端角度, 如果设计单独为色盲和色弱的人设计了一套 UI, 那么尽量通过额外加载 CSS 的方式进行处理. 基础 非色盲, 色弱 色盲, 色弱 普通模式加载 1 + 2, 色彩增强模式加载 1 + 3. 也可以使用普通 + 扩展的方式: 普通 色盲, 色弱 色彩增强模式加载 1, 色彩增强模式加载 1 + 2. 要确保 2 覆盖 1. 模拟与测试 对于 Web 开发来说, 可以通过 Chrome 的开发者工具, 来模拟色盲和色弱. 打开 Chrome 开发者工具. 选择更多工具. Rendering 中, 选择 Emulate vision deficiencies. 可以选择一些情况进行模拟.

2024/12/9
articleCard.readMore

React 19

React 19 终于正式发布了: https://react.dev/blog/2024/12/05/react-19 新版本中新增了许多功能, 其中, 一些功能是我们重点关注的: useActionState use useOptimistic ref 作为 props 传递 useActionState 在使用 useActionState 的时候, 我们需要注意的是, 在函数内部能否调用 setState 函数对数据进行部分修改. 官方演示非常清晰, 这里稍作修改: function DataTable({ name }) { const [result, updateData, isPending] = useActionState( async (previousState, name) => { const result = await getDataPromise(name); return result; }, new Result(), ); return ( <> <Table data={result} isPending={isPending} /> <button type="submit" disabled={isPending} onClick={() => { updateData(name); }} > Update </button> </> ); } use use 仍然不是一定足够可靠的功能. 之前 React 团队就说了 use 的局限性, 现在 React 19 仍然没有解决这个问题. 我们预期仅在初始化数据的时候使用 use, 在更新数据的时候仍使用 useState. 在组件中, 同时保有这两种状态管理的方式, 比如: function MyComponent() { const initData = use(getDataPromise()); // 👆 因为现在不能在渲染组件中创建 Promise, 所以现在会报错 const [data, setData] = useState<Data | null>(null); const currentData = useMemo(() => data ?? initData, [data, initData]); return ( <> {currentData} <button onClick={async () => { const data = await getDataPromise(); setData(data); }} > Set Data </button> </> ); } 不过, 如何我们区分初始化数据和更新数据, 仅在系统初始化数据的时候使用 use, 那么 use 仍然是一个非常有用的功能. 比如: const configPromise = getConfigPromise(); function MyComponent() { const config = use(configPromise); const [data, setData] = useState<Data | null>(null); return ( <> {data} <button onClick={async () => { const data = await getDataPromise(config); setData(data); }} > Set Data </button> </> ); } useOptimistic 在上面的例子中, 我们区分了 initData, data 和 currentData. 在 React 19 中, 我们使用 useOptimistic 可以对前端预计修改成功的数据进行优化. 比如: function MyComponent() { const [data, setData] = useState<Data | null>(null); const [currentData, setOptimisticData] = useOptimistic(data); return ( <> {currentData} <button onClick={async () => { setOptimisticData(tempData); const data = await getDataPromise(tempData); setData(data); }} > Set Data </button> </> ); } 在大多数情况下, 这是一个纯优化, 并不会功能有影响. 这种优化甚至还有负面效果, 比如: 如果用户在点击按钮之后, 已经渲染了新的数据, 这时用户认为已经完成. 然后, 如果后端数据更新失败, 那么数据会重置回错误之前的数据, 但用户不一定会注意到. ref 作为 props 传递 之前, ref 作为 props 传递的时候时会报错. 需要使用 forwardRef 来传递. 但是, 现在 React 19 中, 不再需要使用 forwardRef 来传递, 可以直接传递 ref. 官方演示为: function MyInput({placeholder, ref}) { return <input placeholder={placeholder} ref={ref} /> } //... <MyInput ref={ref} />

2024/12/6
articleCard.readMore

Deno lint 的局限

ESLint 是行业标准. 但是考虑到简洁及效率, Deno lint 没有与 ESLint 做兼容. Deno lint 本身也没有插件机制, 虽然可以向 https://github.com/denoland/deno_lint 贡献规则, 但是生态远远不够好. 目前比较严重的使用上的不足: 缺乏对 JSDoc @deprecated 的支持 只能做单文件检查, 不能建立多文件关联. 不能将注释与代码进行关联, 只能单独对注释或者代码进行检查. 要解决 Deno lint 的这些问题, 可以选择配合 ESLint 同时使用, 但正如 https://github.com/denoland/deno_lint/issues/25#issuecomment-1307626597 所说, 对于 Deno 项目来说, 使用 ESLint 还是会受到一些限制. 即便现在 Deno 实验性支持不写文件后缀名, 但还是有依赖等问题.

2024/12/6
articleCard.readMore

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

在管理实践中, 我们经常会遇到这样的困惑: 为什么精心设计的规则在实际执行中收效不佳? 本文将探讨规则设计与执行的关系. 无论是国家治理还是公司管理, 都可以总结为下面的几点: 设计规则. (立法, 司法) 确保规则被执行. (执法) 按照规则进行. (守法) 针对日常工作存在的问题, 我总想通过制定规则, 然后通过执行这些规则来解决问题. 但我太执着于规则的设计, 而忽略了规则的执行. 有的时候规则没有产生预期的效果, 并不是规则设计的不够精妙, 而是规则执行的不够彻底. 在确保规则被执行的前提下, 再去完善规则才能让规则发挥最大的作用. 如果有令不行, 有禁不止, 那么规则设计的再精妙也是无用.

2024/12/5
articleCard.readMore

隐藏 SSID (Wi-Fi 安全性分析:隐藏 SSID 的作用与局限)

办公室 Wi-Fi 出现问题, 多台终端自动断开连接, 尝试再次连接时提示输入密码. 但是路由器上的有线连接是正常的. 我怀疑是有其他设备使用了相同的 SSID, 并且短时间内信号更强, 让终端设备切换到了这台其他设备. 但我们的 SSID 并不常见, 故意使用我们的 SSID 有什么目的呢? 有可能是为了获得密码. 如果密码是明文传输的, 那么很容易被获取. 但现代的设备不应该这么不安全, 客户端和服务端都应该将其他设备默认为不可信. 比如我们理想中的一种做法是: 客户端构造一个连接请求, 其中包含一个明文随机数, 还有针对这个随机数的根据密码生成的散列值. 服务端收到一个连接请求, 根据明文的随机数计算散列值, 看和数据包中的散列值是否相同, 如果不相同, 则判定为无效连接请求, 如果相同, 则创建一个新的随机数用来将来通信, 并加密后发出. 客户端收到加密的数据后用自身密码解密, 然后使用这个新的随机数作为密码用作本次连接的通信密钥. 上面这套方案就避免了密码在网络间进行明文传输, 同时一定程度上避免重放攻击. 如果想要加强安全性, 还可以在数据包中增加时间戳, 并且定期更换临时通信密钥. 不过回到最初的假设, 如果密码没有明文传输, 伪造的服务端是不是就没有意义呢? 也不全是, 虽然增加了攻击难度, 但是因为有随机数和针对随机数的散列值, 攻击方可以在自己的密码字典中全部计算一遍, 尝试匹配到弱密码, 甚至在散列方法不够安全时进行暴力破解. 对于上述这种方式的攻击, Wi-Fi 有一个方案可以缓解, 就是隐藏 SSID. 但是这种隐藏的作用是有限的, 因为客户端可能会广播 SSID (Probe Request), 攻击方还是可以扫描到. 但是大多数攻击方不会这么做, 因为攻击方可能需要破解多个 AP 的密码, 这么做会大大增加破解难度. 另外, WPA3 增加了一些前向安全的特性, 可以缓解一些基于重放攻击的破解. 建议使用 WPA3 协议.

2024/11/29
articleCard.readMore

GitHub 投票设计

GitHub 投票 GitHub 的投票功能位于 Discussions 中, 有一个分类叫作 Polls. Polls 有基础的投票功能, 但不是表单那种复杂设计. 如果想要自定义分类也可以, 只需要将分类的 Discussion Format 设置为 Poll 即可. 但有两个限制: 已经设置为 Poll 的分类不能修改. 其他分类不能改为 Poll 分类. 所以基本只能在创建分类的时候就选好 Poll 格式. GitHub 的投票相比钉钉/飞书群投票功能区别 GitHub 仅支持不投票即可查看结果功能. GitHub 不支持不投票则不可查看结果功能. GitHub 仅支持匿名投票. GitHub 不支持查看投票者名单功能. GitHub 不支持设置可投票者名单功能. 扩展 2022 年 4 月发布投票功能. https://github.blog/changelog/2022-04-12-discussions-polls/ 也有其他人有上文说到的 “支持查看投票者名单功能” 的需求. https://github.com/orgs/community/discussions/5650

2023/5/1
articleCard.readMore

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

: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 这个库一样.

2022/2/23
articleCard.readMore

Arctic Code Vault Contributor

看 GitHub 很少会看个人页. 知道 Arctic Code Vault Contributor 这件事还是在社区中. 社区中大多数人都有, 我也不例外. 然后看了 GitHub blog 了解了更多. 在2020年2月2日这一天, GitHub 将所有活跃的开源仓库数据进行了快照, 共 21TB. 然后使用 Piql 的技术将数据写入到 186 个光敏胶片中. 最终储存在了挪威 Svalbard 群岛 Longyearbyen 小镇一座废弃矿井的数百米深坑中. 这将保存至少千年. 因为疫情, 时间有一些推迟, 但现在终于还是完成了. 所有相关的代码贡献者都获得了 Arctic Code Vault Contributor 徽章. 我们向自然索取矿石, 现在向自然反馈代码. 想想还是极浪(漫)的. 我身已死, 漏洞长存.

2020/7/17
articleCard.readMore

使用多设备开发时的技巧

多设备开发时, 代码如何同步, 常用偏好如何同步, 怎么方便地进行切换. 这是个课题. 我大概有两种思路: 远程开发机. 编辑器同步设置. 使用远程开发机的做法是最彻底的, 但同时也是存在弊端的. 比如前端开发时使用 8080 端口, 但如果多人使用开发机或者多台开发机所在同一网络, 则会出现冲突. 编辑器同步设置则需要再对多个开发目录进行额外同步, 比如 .ssh/ 和项目 Git 目录. 以下均以 VS Code 为例. 远程开发机 使用 VS Code 扩展 Remote - SSH 可以更加方便地在远程开发机上进行开发. 编辑器同步设置 看到一篇帖子在问如何在多台设备上同步 VS Code 的设置. 我正有此痛点. 在帖子中看到两种做法: 官方自带, 但目前仅限 VS Code Insiders 测试版. 使用扩展. 基于对微软的信任, 有官方的自然用官方的. VS Code Insiders 的图标是青色的, 可以与 VS Code 同时存在. Settings Sync 功能使用起来非常简单, 登录然后选择同步就好了. 这里说一下登录, 和 Live 功能类似, 但以前只有微软账号, 现在 (可能和收购有关系?) 还可以选 GitHub 账号. 如果同时有两个平台的账号, 建议还是选择 GitHub, 因为在使用中发现如果登录失败, 当使用 GitHub 时, 可以通过 code 再次进行登录尝试, 程序员更友好一些吧.

2020/6/9
articleCard.readMore

Node

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 │ └───────────────────────────┘ 阶段概述 定时器:本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。 待定回调:执行延迟到下一个循环迭代的 I/O 回调。 idle, prepare:仅系统内部使用。 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞。 检测:setImmediate() 回调函数在这里执行。 关闭的回调函数:一些关闭的回调函数,如:socket.on(‘close’, …)。 在每次运行的事件循环之间,Node.js 检查它是否在等待任何异步 I/O 或计时器,如果没有的话,则完全关闭。 引用链接: https://nodejs.org/zh-cn/docs/guides/event-loop-timers-and-nexttick/

2020/5/22
articleCard.readMore

Next 50 Years

《未来 50 年》读书总结 前言 《未来 50 年》是一部文集,许多前沿领域的科学家们展望未来 50 年的科学成就和可能有所突破的技术领域。本书正是他们的思考汇聚而成。 本书英文第一版出版于 21 世纪初, 2002 年,距今已经过去 18 年。透过书中的内容我们可以简略的了解到最前沿的科学和其发展方向。学者们对于未来的预测也得以让我们一窥科学发展的趋势。例如,我们对于未来的把握是否过于乐观或悲观。有多少知识是按照我们预想的节奏被发现和总结,又有多少爆炸性的新发现的对我们现有知识系统产生了巨大且深远的影响。 本书的作者大多是最前沿科学研究的学者和专家,涉及到的话题也必然有所局限。在我们大胆的展望未来时,也不应忽略其他基础学科的贡献。 下面是以学科领域的维度列出了本书中作者们提出的问题和见解。 宇宙和太空探索 宇宙大爆炸更详细的解释 占宇宙密度80%到95%的暗物质和暗能量由什么组成 星系如何形成 地球生命是如何开始的 我们有望在月球,火星和环绕木星的轨道上建立基地,源源不断的激发我们的想象力和好奇心。帮助我们探索宇宙的奥秘。 物理学 量子物理的合理解释 引力的量子理论是什么 基本粒子的性质和解释 建立物理学的统一理论 化学 我们将深入认识更小微粒之间的化学反应和相互作用。 医学 越来越多人会变得抑郁。 生活会越来越紧张 通过药物治疗并不是很有效 生物学 生命的定义。我们可能会发现更多能够协同演化的生命系统。更精确的定义生命的本质含义。 对基因的认识和改变。现在实验室能够诱发从小鸡嘴里生出嫩芽,诱发蛇长出腿。到 2050 年,我们有望重构一般恐龙的基因组。 我们将通过机器改善自身。恢复残障人的能力甚至赋予人类更强大的超能力。 神经科学 替换大脑和认知转移 人类如何认识事物 数学 数学证明的观念会发生改变 数学证明最重要的是检验,任何形式的数学证明将被接受。计算机辅助证明也可以被接受。 数学的根本不在于密密麻麻的数字,而在于证明的过程和模式。 复杂性科学 复杂性科学在计算机的帮助下将会有更加显著和切实的发展。 文化教育 我们对于新的观念和认识会变得更加宽容 教育将更加注重个人经验。同时,虚拟技术的发展将使得我们更容易的获取人生经历和体验。 人文道德 一个更新的更现代的基于新的科学研究的道德理论将会产生。以此来规范人们的行为和人类发展的方向。 新的科学将有望完善更精确的人性模型。解答包括行为的主观和客观,感觉的真实和虚拟等问题。 遗传学和认知科学的发展将使得人们更加幸福。本文作者是心理学家,在文中表示将发展一门新的系统的现象学,观察不同人的意识波动规律,使人更加幸福。

2020/5/21
articleCard.readMore

Node Npm Cnpm Yarn Pnpm

node依赖管理 Node的依赖管理工具 npm cnpm yarn pnpm npm 使用一个名为package.json的文件,用户可以通过npm install –save命令把项目里所有的依赖项保存在这个文件里 npm安装插件是从国外服务器下载,受网络影响大,可能出现异常 cnpm cnpm跟npm用法完全一致, 服务器在国内, 访问速度很快 yarn yarn是经过重新设计的崭新的npm客户端,它能让开发人员并行处理所有必须的操作,并添加了一些其他改进 运行速度得到了显著的提升,整个安装时间也变得更少 像npm一样,yarn使用本地缓存。与npm不同的是,yarn无需互联网连接就能安装本地缓存的依赖项,它提供了离线模式。 允许合并项目中使用到的所有的包的许可证 pnpm pnpm运行起来非常的快,超过了npm和yarn pnpm采用了一种巧妙的方法,利用硬链接和符号链接来避免复制所有本地缓存源文件,这是yarn的最大的性能弱点之一 pnpm继承了yarn的所有优点,包括离线模式和确定性安装 引用地址: https://blog.csdn.net/qq_32614411/article/details/80894605

2020/5/18
articleCard.readMore

Js Function

JS的几个常用方法 all 如果数组所有元素满足函数条件,则返回true。调用时,如果省略第二个参数,则默认传递布尔值。 const all = (arr, fn = Boolean) => arr.every(fn); all([4, 2, 3], x => x > 1); // true all([1, 2, 3]); // true allEqual 判断数组中的元素是否都相等 const allEqual = arr => arr.every(val => val === arr[0]); allEqual([1, 2, 3, 4, 5, 6]); // false allEqual([1, 1, 1, 1]); // true currentURL 返回当前访问的 URL 地址。 const currentURL = () => window.location.href; currentURL(); decapitalize 将字符串的首字母转换成小写字母 const decapitalize = ([first, ...rest]) => first.toLowerCase() + rest.join('') decapitalize('Zsqk'); // 'zsqk'

2020/5/15
articleCard.readMore

Deno

DENO 一个 JavaScript/TypeScript 的运行时 deno在5月13日发布1.0版本,经过简单的了解做一个简单的介绍。 Deno简介 deno官网对deno的定义如题,是一个 JavaScript/TypeScript 的运行时,基于Rust(Tokio)和V8引擎。具有默认为安全,开箱即用地支持TypeScript,传送单个可执行文件,具有诸如依赖项检查器(deno info)和代码格式化程序(deno fmt)之类的内置实用程序等等。Deno的哲学旨在为现代程序员提供高效且安全的脚本环境。 Deno与Node比较 在查找deno相关资料时,发现许多诸如deno是node的下一代。那在这里从几个方面介绍,如下: 1、deno和node,从字面意思看就是de和no的位置对换,开发deno的人也正是开发node人。 2、deno不使用npm而是会像浏览器一样使用称为URL或文件路径的模块。 3、Deno不在package.json其模块解析算法中使用。 4、Deno中的所有异步操作均返回承诺。因此,Deno提供的API与Node的不同。 5、Deno需要文件,网络和环境访问的显式权限。这也是默认安全的体现。 6、deno对ts的支持以及打包,测试,测试话等都是原生支持,node需要第三方包来支持。 7、包分发,node中心化npmjs.com,deno去中心化使用import url 总结 个人看法,deno的设计是针对node现存的一些痛点,但是目前node的生态发展已经很完善了,deno短时间替代node不太可能,不过前景还是看好。 官网:https://deno.land githuab:https://github.com/denoland

2020/5/14
articleCard.readMore

HTTP/3

HTTP3 是 HTTP 协议的最新版本。从诞生之初,HTTP 就是交换超文本文档的首选应用层协议。 多年来,为了跟上互联网的发展,以及 WWW 上交换的内容种类增加,HTTP 进行了几次重大升级。 本文将深入探讨 HTTP/3,介绍 HTTP 协议的演变历程,重点介绍 HTTP/3 的特点,并对 HTTP/3 将会带来的互联网变化提供新的视角。 背景 在万维网诞生之时,万维网仅仅是一群交换超文本文件的计算机。在计算机之间交换文件 是一个简单的程序,包括请求和响应。在此基础上设计了一个简单的基于文本的协议。 HTTP(超文本传输协议)应运而生。后来,它被起草成了一个标准化的 IETF 协议, 定义在 RFC 1945 中,也被称为 HTTP/1.0。 多年来,HTTP 从 HTTP/1.0 发展到 HTTP/1.1,再到 HTTP/2。在每一次迭代中, 协议都增加了新的功能,以处理大量的需求,如应用层需求、安全考虑、会话处理和媒体类型等。 要深入了解 HTTP/2 及其从 HTTP/1.0 演变而来的 HTTP/2,请看我们的 HTTP/2 概念文章。 尽管经历了几次修订,但 HTTP 的底层传输机制基本没有变化。但是,随着互联网流量的激增, 在移动电话的推动下,HTTP 的传输机制在保证网页浏览体验的流畅性方面变得问题重重。 HTTP/3 是为了处理 HTTP/2.0 的传输相关问题而生的,可以在各种设备上更快地访问 Web。 它基于一个新的传输层协议,称为 QUIC(Quick UDP Internet Protocol),在 UDP 之上工作。 这一选择与之前版本的 HTTP 截然不同,之前版本都是基于 TCP。TCP 是一个比 UDP 更可靠的协议, 那么为什么要在 UDP 之上重新设计 HTTP 的传输层呢? 让我们来看看在 TCP 上运行 HTTP 的局限性,并深入了解一下基于 QUIC 协议的 HTTP/3 的设计思想。 什么是 HTTP/3 当 IETF 正式标准化 HTTP/2 时,Google 正在独立构建一个新的传输协议,名为 gQUIC。 它后来成为新互联网草案,并被命名为 QUIC。gQUIC 最初的实验证明,在网络条件较差的情况下, gQUIC 在增强网页浏览体验方面的效果非常好。因此,gQUIC 的发展势头越来越好,IETF 的大多数成员赞成建立一个在 QUIC 上运行的 HTTP 新规范。这个新的倡议被称为 HTTP/3, 以区别于当前的 HTTP/2 标准。 从语法和语义上看,HTTP/3 与 HTTP/2 相似。HTTP/3 遵循相同的请求和响应消息交换顺序, 其数据格式包含方法、标题、状态码和 body。然而,HTTP/3 的显著的偏差在于协议层在 UDP 之上的堆叠顺序。 HTTP/3 是如何工作的? HTTP/3 功能的核心是围绕着底层的 QUIC 协议来实现的。在讨论 QUIC 和 UDP 之前, 我们有必要先列出 TCP 的某些限制,这也是导致 QUIC 发展的原因。 TCP 可能会间歇性地挂起数据传输 如果一个序列号较低的数据段还没有接收到,即使其他序列号较高的段已经接收到,TCP 的接收机滑动窗口也不会继续处理。这将导致 TCP 流瞬间挂起,在更糟糕的情况下, 即使所有的段中有一个没有收到,也会导致关闭连接。这个问题被称为 TCP 流的行头阻塞(HoL)。 TCP 不支持流级复用 虽然 TCP 确实允许在应用层之间建立多个逻辑连接,但它不允许在一个 TCP 流中复用数据包。 使用 HTTP/2 时,浏览器只能与服务器打开一个 TCP 连接,并使用同一个连接来请求多个对象, 如 CSS、JavaScript 等文件。在接收这些对象的同时,TCP 会将所有对象序列化在同一个流中。 因此,它不知道 TCP 段的对象级分区。 TCP 会产生冗余通信 TCP 连接握手会有冗余的消息交换序列,即使是与已知主机建立的连接也是如此。 QUIC 协议在以下设计选择的基础上,通过引入一些底层传输机制的改变,解决了这些问题。 1.选择 UDP 作为底层传输层协议。在 TCP 之上建立新的传输机制,将继承 TCP 的上述所有缺点。 因此,UDP 是一个明智的选择。此外,QUIC 是在用户层构建的,所以不需要每次协议升级时进行内核修改。 流复用和流控。QUIC 引入了连接上的多路流复用的概念。QUIC 通过设计实现了单独的、 针对每个流的流控,解决了整个连接的行头阻塞问题。 灵活的拥塞控制机制。TCP 的拥塞控制机制是刚性的。该协议每次检测到拥塞时, 都会将拥塞窗口大小减少一半。相比之下,QUIC 的拥塞控制设计得更加灵活, 可以更有效地利用可用的网络带宽,从而获得更好的吞吐量。 更好的错误处理能力。QUIC 使用增强的丢失恢复机制和转发纠错功能,以更好地处理错误数据包。 该功能对于那些只能通过缓慢的无线网络访问互联网的用户来说是一个福音, 因为这些网络用户在传输过程中经常出现高错误率。 更快的握手。QUIC 使用相同的 TLS 模块进行安全连接。然而,与 TCP 不同的是,QUIC 的握手机制经过优化,避免了每次两个已知的对等者之间建立通信时的冗余协议交换。 灵活的拥塞控制机制。TCP 的拥塞控制机制是刚性的。该协议每次检测到拥塞时, 都会将拥塞窗口大小减少一半。相比之下,QUIC 的拥塞控制设计得更加灵活, 可以更有效地利用可用的网络带宽,从而获得更好的吞吐量。 更好的错误处理能力。QUIC 使用增强的丢失恢复机制和转发纠错功能,以更好地处理错误数据包。 该功能对于那些只能通过缓慢的无线网络访问互联网的用户来说是一个福音,因为这些 网络用户在传输过程中经常出现高错误率。 更快的握手。QUIC 使用相同的 TLS 模块进行安全连接。然而,与 TCP 不同的是,QUIC 的握手机制经过优化,避免了每次两个已知的对等者之间建立通信时的冗余协议交换。 为什么 HTTP/3 很重要? TCP 已经有 40 多年的历史了。它在 1981 年通过 RFC 793 从而标准化。多年来, 它经历了多次更新,是一个非常强大的传输协议,可以支持互联网流量的增长。然而, 由于设计上的原因,TCP 从来就不适合处理有损无线环境中的数据传输。在互联网的早期, 有线网络将网络中的每一台计算机连接起来。 现在,随着智能手机和便携式设备的数量超过台式机和笔记本电脑的数量,超过 50% 的互联网流量已经通过无线传输。这种趋势给整体的网络浏览体验带来了问题, 其中最重要的是在无线覆盖率不足的情况下,TCP 中的行头阻塞。 Google 的一些初步实验证明,QUIC 作为 Google 部分热门服务的底层传输协议, 极大地提高了速度和用户体验。部署 QUIC 作为 YouTube 视频的底层传输协议,导致 YouTube 视频流的缓冲率下降了 30%,这直接影响了用户的视频观看体验。在显示谷歌搜索结果时, 也有类似的改善。 网络条件较差的情况下提升非常明显,这促使谷歌更加积极地完善该协议,并最终向 IETF 提出标准化。 由于这些早期的试验所带来的所有改进,QUIC 已经成为带领万维网走向未来的重要因素。 在 QUIC 的支持下,HTTP 从 HTTP/2 到 HTTP/3 的改头换面,朝着这个方向合理地迈出了一步。 HTTP/3 的最佳用例 HTTP/3 将改善我们上网的体验,特别是在仍无法使用高速无线网络的地区。尽管 HTTP/2 已经解决了一部分问题,然而 HTTP/3 更进一步。 物联网(IoT) HTTP 可能不是物联网的首选协议,但在某些情况下,基于 HTTP 的通信非常适合特定的应用。 HTTP/3 可以解决从传感器收集数据的移动电话的无线连接损耗问题。这个问题同样适用于 安装在车辆或可移动资产上的独立 IoT 设备。通过 HTTP 来访问这些设备,可以更加可靠。 大数据 全球各地的企业都在觉醒,意识到从多个部门收集数据的潜力,并将其整合成更大的信息共享 API, 供内部和外部受众共享。这些 API 也为数据的货币化铺平了道路,通过托管这些数据作为流 API 服务可以实现数据的货币化。随着时间的推移,这些服务会吐出海量的数据。通过 HTTP/3 托管的流 API 将使它们比 HTTP/2 更健壮、更有弹性。 Web VR 随着浏览器能力的提升,内容格局正在快速变化。其中一个领域就是基于网络的 VR。 虽然还处于起步阶段,但有很多的用例可以让 VR 在加强协作方面发挥关键作用。 网络在促进 VR 互动方面占据了核心位置。VR 应用需要更多的带宽来渲染虚拟场景中的复杂细节, 因此迁移到 HTTP/3 会大有收获。 采用 HTTP/3:考虑和限制 过渡到 HTTP/3 不仅涉及到应用层的变化,还涉及到底层传输层的变化。因此,与它的前身 HTTP/2 相比,HTTP/3 的采用更具挑战性,因为后者只需要改变应用层。传输层承受着 网络中的大量中间层审查。这些中间层,如防火墙、代理、NAT 设备等会进行大量的 深度数据包检查,以满足其功能需求。因此,新的传输机制的引入对 IT 基础设施和 运维团队来说有一些影响。 然而,HTTP/3 被广泛采用的另一个问题是,它是基于 QUIC 的,在 UDP 上运行。大多数的 Web 流量,以及 IETF 定义的知名服务都是在 TCP 之上运行的。这也是为什么长时间运行 HTTP/3 的 UDP 会话会被防火墙的默认数据包过滤策略所影响的原因。 随着 IETF 正在进行的标准化工作,这些问题最终都会得到解决。此外,考虑到 Google 在早期 QUIC 实验所显示的积极结果,人们对 HTTP/3 的支持是压倒性的, 这将最终迫使中间层厂商标准化。 针对受限的 IoT 设备,HTTP/3 由于过于繁琐从而无法采用。许多 IoT 应用部署的设备的 外形尺寸非常小。因此,它们的 RAM 和 CPU 功率都是有限的。为了使设备在电池功率、 低比特率和有损连接等限制条件下高效运行,必须执行此要求。HTTP/3 在现有的 UDP 之上, 以 QUIC 的形式在传输层处理,增加了 HTTP/3 在整个协议栈中的占用空间。这使得 HTTP/3 较为笨重,不适合那些 IoT 设备。但这种情况很少出现,而且存在专门的协议,这就避免了 直接在此类设备上支持 HTTP 的需要。此外,还有以物联网为核心的协议,如 MQTT。 开始使用 HTTP/3 IETF 的 HTTP 工作组正致力于在 2020 年后期发布 HTTP/3。因此它还没有被 NGINX 和 Apache 等主流 web 服务器正式支持。不过,有几个 lib 可以用来实验这个新协议, 也提供了非官方的补丁。 以下是支持 HTTP/3 和 QUIC 传输 lib 的列表。请注意,这些实现都是基于互联网标准草案 某一个版本,而这个版本很可能会被更高的版本所取代,最终的标准会在 RFC 中发布。 Quiche (https://github.com/cloudflare/quiche) Quiche 提供了通过 QUIC 协议发送和接收数据包的底层编程接口。它还支持 HTTP/3 模块, 通过其 QUIC 协议实现发送 HTTP 数据包。除此之外,它还为 NGINX 服务器提供了一个 非官方的补丁,可以安装和托管一个能够运行 HTTP/3 的 Web 服务器。除此以外, 还提供了额外的程序来支持 Android 和 iOS 移动应用上使用 HTTP/3。 Aioquic (https://github.com/aiortc/aioquic) Aioquic 是 QUIC 的 python 实现。它还内置 HTTP/3 的测试服务器和客户端库。Aioquic 建立在 asyncio 模块之上,asyncio 模块是 Python 的标准异步 I/O 框架。 Neqo (https:/github.com/mozilla/neqo) Neqo 是 Mozilla 使用 Rust 实现 QUIC 和 HTTP/3。 原文地址:https://www.ably.io/concepts/http3?utm_medium=referral&utm_source=reddit&utm_campaign=evergreen#limitations 引用地址:https://mp.weixin.qq.com/s/i-QUbVRVicqzMSZ9FUVCfQ 评论: 有人说, 当他们身在中国大陆使用 UDP 服务时会被 QoS 限流. 虽说是将来的标准, 但整体来说, 这还是未来式. 我们可以通过 https://caniuse.com/#feat=http3 来了解浏览器对其的支持情况.

2020/5/13
articleCard.readMore

closure

闭包 函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。 参考:MDN 闭包的特性 函数嵌套函数 函数内部可以引用函数外部的参数和变量 参数和变量不会被垃圾回收机制回收 闭包的作用 可以在函数的外部访问到函数内部的局部变量。 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。 例子 比如我们定义一个计数器,正常的写法 var count = 0; function add() { return count += 1; } add(); // 1 add(); // 2 这样没问题,可以正常实现功能,也很简单方便。但是如果我们要同时实现多个计数器呢,总不能 var count = 0; function add() { return count += 1; } var count1 = 0; function add1() { return count += 1; } var count2 = 0; function add2() { return count += 1; } ... 这样一直写吧, 所以这时候就可以使用闭包来实现 function add() { var count = 0; return function() { return count += 1; } } var fn1 = add(); // 计数器1 var fn2 = add(); // 计数器2 fn1(); // 1 fn1(); // 2 fn1(); // 3 fn2(); // 1 fn2(); // 2 fn2(); // 3 最后总结一下闭包的好处与坏处 好处 保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存) 匿名自执行函数可以减少内存消耗 坏处 其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null; 其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

2020/5/12
articleCard.readMore

Headless Brower

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 库应用场景 页面自动化测试 爬虫 保存页面副本 总之,Chrome 浏览器能够实现的功能在 Headless 模式中都可以实现。加入程序使得我们可以实现更多更强大的功能。 参考 Getting Started with Headless Chrome Chrome DevTools Protocol chromedp selenium puppeteer

2020/5/11
articleCard.readMore

如何用 CSS 自定义使用 Font Awesome 图标

最近想在 CSS ::after 中直接使用 Font Awesome 图标. 我们可以直接看代码了解如何去使用, 也可以通过 Font Awesome 官方的文章. 具体实现就是: .need-after::after { font-family: "Font Awesome 5 Free"; content: "\f007"; } 其中 content 的值可以直接在 gallery 中找到. 附: CSS 的编码 这里顺便说一下 CSS 的编码. 对于一些编程语言来说, 比如 a 会使用 \u0061 这样编码, 其中 u 代表 Unicode. 但 CSS 没有, 虽然编码方式也是 UTF, 但储存方式是固定的 6 个 hex, 比 UTF-32 少了两个储存位置. 比如 a 在 CSS 中可以写为 \000061.

2020/5/9
articleCard.readMore

Cloudwatch

什么是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函数

2020/5/8
articleCard.readMore

Awesome

awesome系列github上超有名的Topic 大部分有一定知名度的领域,都有着自己的awesome-xxx项目 awesome Topic简要的事实描述 1、目前awesome系列包含了3325个各类仓库 要了解这个系列,可以直接从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示例和中间产品列表)

2020/5/6
articleCard.readMore

关于使用 PostgreSQL 的 ENUM 类型

数据库版本 v9.6 数据库中枚举值的作用 约束数据. 更加语义化. 在数据库中使用枚举值只是在数据层面确保数据正确的做法, 不能替代程序中的逻辑. 程序中应该做足够的判断, 尽量确保数据库中不会出现因枚举值不匹配导致的问题. 关于枚举值的使用 例如: CREATE TYPE abc AS ENUM ('a', 'b', 'c'); 虽然在向数据库中写数据时, 我们是将 'a' 写入到数据库中, 但实际数据库储存的是 abc[1] 这样的数据. 关于枚举值的查询 如何查询目前数据库中已经有的枚举值是哪些. 可以参考 Stack Overflow 上的回答, 效率还是比较高的, 基本 10ms 以内. SELECT n.nspname AS enum_schema, t.typname AS enum_name, t.oid AS enum_id, e.enumlabel AS enum_value FROM pg_type t JOIN pg_enum e ON t.oid = e.enumtypid JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace ORDER BY enum_name, e.enumsortorder; 关于枚举值的修改 支持添加新值. 支持修改原值. 不支持删除原值. 虽然文档说支持向后添加新值, 但实际可以加在任何地方. 虽然文档写不支持修改排序, 但可以通过修改 enumsortorder 来完成重排序. 并且排序 支持浮点数, 比如当执行 ALTER TYPE abc ADD VALUE a- BEFORE b 时, 会将新插入值的排序改为浮点数, 如 1.5. 关于如何修改枚举值, 直接 UPDATE pg_enum 就可以了. 能否直接修改原值的排序呢? 实测是没问题的, 不会影响表中使用到该类型的数据.

2020/4/30
articleCard.readMore

404 Page

一行暖心的代码,让世界充满爱~ 有时用户在访问页面找不到网站的资源时,就会提示404错误。作为网站的开发者,最好应该自己定制404页面,引导用户返回到网站,防止用户流失。 你知道吗? 在自己定制404页面时,只需要在网站中加入一行代码,就能为公益尽一份力。这个页面叫做公益404页面 介绍 公益404页面是由腾讯公司员工志愿者自主发起的互联网公益活动。 网站只需要在自己的404页面中嵌入一段简单的代码,就能通过互联网来迅速传播失踪儿童信息,从而提高找回失踪儿童的概率。失踪儿童信息来自宝贝回家寻子网。 代码 复制以下 js 代码,嵌入到您的 404 页面,可以自适应移动设备 注意事项 如果一个 404 页面的内容小于 512B,IE 会认为该 404 页面不够友好,在 IE 下将不会成功返回该 404 错误页面 <script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8"></script> 同时homePageUrl、homePageName两个参数,提高页面定制性 <script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8" homePageUrl="返回页面路径" homePageName="返回页面名称"></script> 文章内容参考::https://www.qq.com/404/

2020/4/30
articleCard.readMore

Pm Em Rem

在css中单位长度用的最多的是px、em、rem,这三个的区别是:   px是固定的像素,一旦设置了就无法因为适应页面大小而改变。   em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定死了的,更适用于响应式布局。 对于em和rem的区别一句话概括:em相对于父元素,rem相对于根元素 rem中的r意思是root(根),这也就不难理解了 em 子元素字体大小的em是相对于父元素字体大小 元素的width/height/padding/margin用em的话是相对于该元素的font-size ``` 我是孙元素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 */ } ```

2020/4/29
articleCard.readMore

ECMAScript 中的相等

相等 Strict Equality Comparison === 严格相等 Abstract Equality Comparison == 大概相等 SameValueZero SameValue === 与 == 的区别 如果两值类型相等, 则两种对比没有区别. == 的主要功能是隐性地类型转换. 如果一个为 Number 另一个为 String, 则将 String 转为 Number 类型进行对比. 如果任意一个为 Boolean, 则将 Boolean 转为 Number 类型进行对比. 如果任意一个为 Object, 则调用 .toString() 转类型. 转为 Number 类型时, 需要注意: true => 1, false => +0, null => +0. 总结如下: 类型 转换 null 不转换 undefined 不转换 Number 不转换 String 转为 Number Object 转为 String true 1 false +0 依据上面的规则, 我们可以得到以下结果. null == undefined; "[object Object]" == {}; 1 == true; 2 !== true; 0 == false; -1 !== false; NaN == "NaN"; !({} == true); !({} == false); 有些是我们想要的, 但有些不是. 因为这种类型转换的复杂性, 不建议使用 ==. SameValueZero 与 SameValue 的区别 主要区别在于是否区分 -0 与 +0. SameValue 区分, SameValueZero 则不区分. 这是历史遗留问题, 我们一般不会直接遇到该问题. === 与 SameValueZero 的区别 主要区别在于是否区分两个 NaN, === 区分, SameValueZero 则不区分. 赋值 整个 Assignment Operators 比较复杂, 简单说运算符右侧使用的 GetValue. 如果不是引用类型, 则只是返回该值就好. 如果是引用类型, 则将该值复制. 如果右侧为对象, 则创建该值的引用. 深度对比与不可变值 概念: deep copy deep equal memoization immutable object 应用: JSON.stringify lodash/isEqual memoize-one immutability-helper 结论 一般来说, 我们避免使用 ==, 要使用 ===. 在处理复杂对象同时为了优化性能时, 我们会使用 memo 的方法, 但如何更好判断依赖项 是否发生了变化, 我们只要在每次变化时, 把这个复杂对象当作 immutable object 就好. 当我们使用了 immutable object, 就不再那么需要 deep copy 和 deep equal 了.

2020/4/28
articleCard.readMore

Jamstack

什么是 Jamstack 只是一个概念, 可以描述一类架构. JAM = JavaScript + APIs + Markup 在网页应用中, HTML 是通用的 Markup language. 首先前后端分离, 不是 PHP 擅长的那种服务器端渲染. 然后需要将前端代码自动构建为 HTML 及相关部署在 CDN 上. 标准写法 按说, 完整的写法应该是 J.A.M. Stack, 简单的写法是 JAMStack 或 JAMstack. 但是 jamstack.org 和 Netlify 给出的写法是 Jamstack. 我们的经验 我们曾用过 Next.js 的 Static Exporting 功能做过类似的网站. 但还是有一些的限制的, 后来就再没用过. 现在我们更倾向于 code splitting + lazy loading 这种方案. 与 JAM 最大的不同就是 没有 M. 不是在构建的时候生成了多个 HTML, 还是用 JavaScript 生成 DOM, 也就是 Markup. 我们选择不使用静态 HTML 的问题主要是路由, 普通内容站可以说在构建的时候就规划好了 所有页面, 但功能性站点可不是. 比如一个用户的信息页面我们希望是 https://site/people/jim, 但我们在构建的时候 并不真的清楚有多少个用户, 用户都在 API 中获取. 如果要用 HTML 页面和普通 CDN, 我们只能选择 https://site/people?user=jim 这样的方式. 结论 Jamstack 仅适用于内容型站点. 类似的概念不是什么新东西了, 大多数 CMS 都是这样的. Jamstack 渊源 Jamstack 是由 Netlify 提出的概念. 在 Netlify 的网站上, 有专门介绍 Jamstack 的页面: https://www.netlify.com/jamstack/. 对于内容展示型网站来说, 如果能遵循原子部署, 那么即便数据量巨大, 理论上也是可以 使用 Jamstack 的.

2020/4/27
articleCard.readMore

Photoshop Sharpens Image

Photoshop使用智能锐化将图片变清晰 1.首先打开PS并打开一张图片,复制一个图层 2.然后点击菜单栏上的滤镜,下面的锐化,选择锐化下面的智能锐化 3.点击智能锐化后,先将移去设置成高斯模糊,然后根据自己的需求调整数量,半径,杂色,最后按确定,然后可以放大细节对比一下。

2020/4/23
articleCard.readMore

Site By Station Gadgets

前一段时间同事找我扒网站 然后K同学推荐了这个仿站小工具8.1 现在分享给大家 介绍 仿站小工具8.1是一款用来下载网页模板的软件,可以将指定目标网站的资源内容快速索引读取并复制到本地使用的软件工具!可以通过该软件检测网编码,下载网页,它会从html的代码中将JS、Css、Image、Picture、Flash等静态文件网址提取过来,再从下载完好的Css代码中提取出Image静态文件网址,通过网址下载静态文件,根据软件设置好的保存规则,自动修正html和css代码链接路径,最终这些静态文件被按分类保存到电脑文件夹。并且会自动分类归档。 软件特色 1. 从输入的网址下载html代码。 2. 支持提取JS、Css、Image、Picture、Flash等静态文件网址。 3. 可根据软件设置好的保存规则,自动修正html和css代码链接路径。 使用教程 输入需要下载的网页的网址,点击添加。 选择保存地址,点击开始下载。 等待下载完成,打开保存地址里面的文件就可以了。

2020/4/22
articleCard.readMore

编程题 聒噪的青蛙

写业务代码, 可能会碰到一些架构上的问题, 但性能不是重点, 很少接触真正的算法. 最近听播客, 道长介绍在硅谷面试时, 一般初级软件工程师就是算法题, 资深之后 才会有架构题, 越资深算法就越不重要. 但代码与性能是一方面, 另一方面, 能否理解问题, 解决问题, 这是任何人都需要的. 我们的前端笔试题已经很久没更新了, 后端则没有正式的笔试题. 春季招聘正需要, 就打算去 LeetCode 上抄那么几道题应对招聘. 最近的一道中等难度的题是: Minimum Number of Frogs Croaking 根据 Hints, 用 JavaScript 写了答案, 思路应该是清晰的, 效率也可以接受. 参考 Hints 写的答案都是基础方法, 但软件工程应该就是使用最简单的思路去解决问题. 以下是具体答案: Runtime: 76 ms, faster than 85.98% of JavaScript online submissions. Memory Usage: 37.1 MB, less than 100.00% of JavaScript online submissions. (2020-04-22 17:22:18 +8) /** * @param {string} croakOfFrogs * @return {number} */ var minNumberOfFrogs = function (croakOfFrogs) { let max = 0; const m = { c: 0, r: 0, o: 0, a: 0, k: 0 }; for (const v of croakOfFrogs) { if (!"croak".includes(v)) { return -1; } if (v === "k") { m.c -= 1; m.r -= 1; m.o -= 1; m.a -= 1; if (m.c >= max) { max = m.c + 1; } } else { m[v] += 1; if (m.c < m.r || m.r < m.o || m.o < m.a || m.a < m.k) { return -1; } } } if (m.c !== 0) { return -1; } return max; }; 附 这里给出一些我用过的测试: const test = [ ["cccroacrkroakroakcroakoak", 4], ["cccroacrkroakroakcroakaok", -1], ["croakcrook", -1], ["croakcroak", 1], ["croakcroa", -1], ["croakcroac", -1], ]; for (const [v, r] of test) { const it = minNumberOfFrogs(v); if (it !== r) { throw new Error(`${v} 的结果应该为 ${r}, 却是 ${it}`); } } 我最初的答案是这样的: /** * @param {string} croakOfFrogs * @return {number} */ var minNumberOfFrogs0 = function (croakOfFrogs) { return croakOfFrogs .split("k") .map((v) => cDisplayTime(v)) .reduce((acc, v) => { if (v > acc) { return v; } return acc; }, 0); }; function cDisplayTime(str) { let count = 0; for (const v of str) { if (v === "c") { count += 1; } } return count; } 这个答案性能不是重点, 看起来也更简单. 但不能找出错误参数. 然后我才意识到, 这道题麻烦的是校验错误. 然后老老实实依照 Hints 写了最终的答案. Hints: keep the frequency of all characters from “croak” using a hashmap. For each character in the given string, greedily match it to a possible “croak”. 更新 第二天早上又花了一点时间写了两个版本: 通用版: https://leetcode.com/submissions/detail/328828305/ 性能版: https://leetcode.com/submissions/detail/328832285/ 再翻看大家的讨论, 看到其他语言基本与我的性能版思路一致, 但通用版大家都没怎么写. 在我目前的实际工作中, 性能要求并不高, 我们更期望可读性强的代码. 这道题前前后后, 写代码, 整理思路, 发帖, 花了两三个小时, 我想 改动一下是可以作为笔试题了. 通用版代码就不写了, 以下是性能版源代码: /** * @param {string} croakOfFrogs * @return {number} */ var minNumberOfFrogs = function (croakOfFrogs) { // 多出的数量 let max = 0; // 储存鸣叫数量 let c = 0; let r = 0; let o = 0; let a = 0; let k = 0; for (let i = 0; i < croakOfFrogs.length; i++) { const v = croakOfFrogs[i]; switch (v) { case "c": c += 1; break; case "r": r += 1; if (r > c) { return -1; } break; case "o": o += 1; if (o > r) { return -1; } break; case "a": a += 1; if (a > o) { return -1; } break; case "k": k += 1; if (k > a) { return -1; } if (c - k > max) { max = c - k; } break; default: return -1; } } if (c !== k) { return -1; } return max + 1; };

2020/4/22
articleCard.readMore

Rabbitmq

RabbitMQ 简介以及使用场景 RabbitMQ 简介 MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。 消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。 RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。 RabbitMQ 使用场景 解耦(为面向服务的架构(SOA)提供基本的最终一致性实现) 场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。 传统模式的缺点: 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败 引入消息队列: 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功 库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作 假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦 为了保证库存肯定有,可以将队列大小设置成库存数量,或者采用其他方式解决。 基于消息的模型,关心的是“通知”,而非“处理”。 短信、邮件通知、缓存刷新等操作使用消息队列进行通知。 消息队列和RPC的区别与比较: RPC(远程过程调用:Remote Procedure Call): 异步调用,及时获得调用结果,具有强一致性结果,关心业务调用处理结果。 消息队列:两次异步RPC调用,将调用内容在队列中进行转储,并选择合适的时机进行投递(错峰流控) 异步提升效率 场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式 (1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端 (2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间,引入消息队列,将不是必须的业务逻辑。 流量削峰 流量削峰也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛 应用场景:系统其他时间A系统每秒请求量就100个,系统可以稳定运行。系统每天晚间八点有秒杀活动,每秒并发请求量增至1万条,但是系统最大的处理能力只能每秒处理1000个请求,于是系统崩溃,服务器宕机。 之前架构:大量用户(100万用户)通过浏览器在晚上八点高峰期同时参与秒杀活动。大量的请求涌入我们的系统中,高峰期达到每秒钟5000个请求,大量的请求打到MySQL上,每秒钟预计执行3000条SQL。 但是一般的MySQL每秒钟扛住2000个请求就不错了,如果达到3000个请求的话可能MySQL直接就瘫痪了,从而系统无法被使用。但是高峰期过了之后,就成了低峰期,可能也就1万用户访问系统,每秒的请求数量也就50个左右,整个系统几乎没有任何压力。 引入MQ:100万用户在高峰期的时候,每秒请求有5000个请求左右,将这5000请求写入MQ里面,系统A每秒最多只能处理2000请求,因为MySQL每秒只能处理2000个请求。 系统A从MQ中慢慢拉取请求,每秒就拉取2000个请求,不要超过自己每秒能处理的请求数量即可。MQ,每秒5000个请求进来,结果只有2000个请求出去,所以在秒杀期间(将近一小时)可能会有几十万或者几百万的请求积压在MQ中。 关于流量削峰:秒杀系统流量削峰这事儿应该怎么做? 这个短暂的高峰期积压是没问题的,因为高峰期过了之后,每秒就只有50个请求进入MQ了,但是系统还是按照每秒2000个请求的速度在处理,所以说,只要高峰期一过,系统就会快速将积压的消息消费掉。我们在此计算一下,每秒在MQ积压3000条消息,1分钟会积压18万,1小时积压1000万条消息,高峰期过后,1个多小时就可以将积压的1000万消息消费掉。 引入消息队列的优缺点 优点 优点就是以上的那些场景应用,就是在特殊场景下有其对应的好处,解耦、异步、削峰。 缺点 系统的可用性降低 系统引入的外部依赖越多,系统越容易挂掉,本来只是A系统调用BCD三个系统接口就好,ABCD四个系统不报错整个系统会正常运行。引入了MQ之后,虽然ABCD系统没出错,但MQ挂了以后,整个系统也会崩溃。 系统的复杂性提高 引入了MQ之后,需要考虑的问题也变得多了,如何保证消息没有重复消费?如何保证消息不丢失?怎么保证消息传递的顺序? 一致性问题 A系统发送完消息直接返回成功,但是BCD系统之中若有系统写库失败,则会产生数据不一致的问题。 总结 所以总结来说,消息队列是一种十分复杂的架构,引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避。引入MQ系统复杂度提升了一个数量级,但是在有些场景下,就是复杂十倍百倍,还是需要使用MQ。

2020/4/21
articleCard.readMore

2019 年中 社交媒体中最流行的语言是?

最近看到 PHP 核心开发成员 Laruence 在微博聊语言喷子. 我是非常赞同他的基本观点的, 语言只是解决问题的具体实施细则, 更重要的不是语言本身, 而是解决问题的抽象方法. 下面这则 2019 年的排行还是可以看出 PHP 仍在一阵. https://redmonk.com/sogrady/2019/07/18/language-rankings-6-19/ 参考两个社交媒体: GitHub Stack Overflow X 轴的 GitHub 可以代表开源流行度. Y 轴的 Stack Overflow 可以代表新人活跃度. x + y 为总流行度, x > y 是更硬核的语言, x < y 是更大众的语言. 可以看出 Rust 开源流行但新人问题少. (相对) Visual Basic 新人问题多但开源不够流行. (相对)

2020/4/20
articleCard.readMore

Data Encapsulation And Unencapsulation

OSI七层模型下四层的数据封装和解封装 osi七层模型的下四层数据封装是了解各个传输协议以及数据传输方式的基础 OSI七层模型下四层模型 传输层 传输层的数据格式为数据报文,主要做的处理是将数据进行分段,然后每个报文的头部会添加报文头信息,包含数据完整性的信息。报文大小由主机的吞吐量,带宽以及一次处理的字节数等限制的。传输层的主要协议有TCP,UDP等。其中TCP的三次握手建立起逻辑通路以后就开始将分好的数据报文,在收到报文以后根据报文头来检查数据的完整性。 网络层 网络层的数据格式为数据包,对传输层分装好的数据报文再进行封装。这一步是在报文的头部添加包头,包含一些ip的寻址的信息。在网络层专属的过程中,路由器只对数据包头进行检查,然后进行分组转发。 数据链路层 数据链路层的数据格式为数据帧,对路由层的封装好的数据包进行再封装。这一步是在数据包头部添加数据帧的头部信息,主要包含硬件地址寻址等信息。 物理层 物理层主要是根据各种协议将数据转换成物理信号进行传输。802协议族,其中802.3是以太网,802.11n是无线局域网(WIFI)。 OSI数据封装和解封装 封装 发送数据, 按照 传输层->网络层->数据链路层 的顺序为数据封装。一般发生在发送发 解封装 接受数据, 按照 数据链路层->网络层->传输层 的数据为解封装。一般发生在接收方。中间经过的路由器和交换机一般只会对数据进行检查不会改变数据。

2020/4/17
articleCard.readMore

Zeit Now

Zeit-now部署静态项目 现在ZEIT 是一个云平台静态站点和无服务器功能完美地与您的工作流程适合。它使开发人员可以托管Jamstack网站和Web服务,这些网站和Web服务可以立即部署,自动扩展并且不需要任何监督,而且都无需配置。 注册 注册链接:https://zeit.co/,首先需要前往zeit官网进行用户注册,当然我们也可以用gitlab,github等等方式来进行登录,这也是使用该工具的一个前提条件 安装 在命令行工具执行npm install now -g,进行now的全局安装。 使用方法 本地命令行 1.命令行工具进入项目,运行now命令 2.根据提示进行配置 3.配置完成后会看到一行products提示网站链接地址,复制该地址,即可直接访问部署的项目 zeit官网项目部署 1.进入https://zeit.co/并登录。 2.进入个人Owerview页面,选择Import Project 3.可从gitlab,github等导入已有项目,或者可以选择模板导入项目 zeit支持框架及语言 Node.js Go Python Ruby Next.js Vue.js Ionic Angular Angular Ionic React Nuxt.js … 更多参考:https://zeit.co/docs

2020/4/16
articleCard.readMore

GitHub 免费版不限私有仓库及协作者数量

当地时间2020年04月14日, GitHub 发文 GitHub is now free for teams. Free 不再限制私有仓库及协作者数量. Team 降价为每人每月 4 美元. 目前 Free 与 Team 的限制主要是私有仓库的工作流了. 具体差别可以看 1. 这里列举一些我认为重要的: 合并代码前强制要求 review. 可为 issue 或 PR 指定多位 assignees. 自动指定 code owners 进行 review. GitHub 的这次变动主要瞄准的应该是 GitLab 的用户. 从价格上做到了不输于 GitLab. 但究竟有多少企业用户会转而选择 GitHub 呢? 我不知道. 我们现在在用 GitLab, 暂时不会转. Update 2020-04-23: 顺便提一下 GitLab 官方对 GitHub 此次行为的回应: https://about.gitlab.com/blog/2020/04/14/github-free-for-teams/ 然后我最近发现之前已经给过体验机会的 Gold 计划再次免费 30 天. Free Trial of GitLab.com Gold Try all GitLab has to offer for 30 days. No credit card required.

2020/4/16
articleCard.readMore

倪光南

《不老人生》第五集 倪光南 | CCTV纪录 https://www.youtube.com/watch?v=VP6evXzB_dE 倪光南在参与过计算机设计之后就转到了汉字信息处理方向. 倪光南 1999 年回到计算机所. (离开联想) 倪光南说现在开始追赶芯片设计还有机会. (我 99% 不信) 倪光南说, 行业中有挺多穿马甲的国产技术, 也就是国外的技术加个了壳. (太对了) 倪光南说, 做国产技术评测得罪过一些人. 倪光南说自己现在更重视软件. 倪光南现在是用 iPhone 的. (具体版本不知道, 但带刘海) 柳倪之争 在纪录片中, 更像是宣传片, 没有讲到倪光南在联想的时光. 且不说当初到底谁对谁错, 历史也不能假设. 但有两点可以确认: 倪光南选择举报柳传志个人, 最后被裁定 “没有材料证明柳传志同志存在个人经济问题”. 倪光南被赶出了联想, 没股票.

2020/4/15
articleCard.readMore

Css Filter

CSS3: fitler属性 filter 属性定义了元素(通常是)的可视效果(例如:模糊与饱和度)。 Filter 函数 注意: 滤镜通常使用百分比 (如:75%), 当然也可以使用小数来表示 (如:0.75)。 |Filter | 描述 |—|—| |none|默认值,没有效果| |blur(px)|给图像设置高斯模糊。”radius”一值设定高斯函数的标准差,或者是屏幕上以多少像素融在一起, 所以值越大越模糊;如果没有设定值,则默认是0;这个参数可设置css长度值,但不接受百分比值。| |brightness(%)|给图片应用一种线性乘法,使其看起来更亮或更暗。如果值是0%,图像会全黑。值是100%,则图像无变化。其他的值对应线性乘数效果。值超过100%也是可以的,图像会比原来更亮。如果没有设定值,默认是1| |contrast(%)|调整图像的对比度。值是0%的话,图像会全黑。值是100%,图像不变。值可以超过100%,意味着会运用更低的对比。若没有设置值,默认是1。| |grayscale(%)|将图像转换为灰度图像。值定义转换的比例。值为100%则完全转为灰度图像,值为0%图像无变化。值在0%到100%之间,则是效果的线性乘子。若未设置,值默认是0;| 那么这些网站到底是如何实现网页变灰呢? 很简单,只需要在页面中插入一行CSS代码 <style> html { filter: grayscale(1); } </style>

2020/4/15
articleCard.readMore

Chrome Plug

Chrome便捷插件 我们都知道Chrome 浏览器有一个好处,就是插件极其丰富。 Octotree 树形展示 Github 项目代码 GitHub网页连个侧栏的文件树没有,查看很累,现在有很多开发者还是需要git clone下载到本地在把代码装到开发工具里才能愉快的阅读代码。 这款Octotree让你能像在GitHub上像在你的开发工具里一样浏览和搜索代码。 下载地址:https://chromecj.com/web-development/2017-10/840.html 「FeHelper」WEB前端助手 目前包括 JSON自动/手动格式化、JSON内容比对、代码美化与压缩、信息编解码转换、二维码生成与解码、图片Base64编解码转换、Markdown、 网页油猴、网页取色器、脑图等贴心工具. 下载地址:https://chromecj.com/web-development/2018-01/879.html Fatkun图片批量下载 找出当前页面的所有图片,提供按分辨率、链接等筛选图片,只需点击一下,即可下载页面上选择的所有图像。可以使用你自己的规则下载图像列表,可以批量重命名下载的图像 下载地址:https://chrome.google.com/webstore/detail/fatkun-batch-download-ima/nnjjahlikiabnchcpehcpkdeckfgnohf?hl=zh-CN Baidu Capsule(百度网站净化) 使用更纯净的百度,包括这几个功能: 1.屏蔽百度推广(就是为了它) 2.阻止百度追踪 3.美化首页(个人感觉没有用,很丑) 下载地址:https://chrome.google.com/webstore/detail/%E7%99%BE%E5%BA%A6%E8%8D%AF%E4%B8%B8-baidu-capsule/ngiclcoldiplnjcafhjkacjcmdidcmjp?hl=zh-CN PS:还有一款自己在用的鼠标快捷指令工具(windows):Quicker。 下载地址:https://getquicker.net/ 脚本地址:https://getquicker.net/Share/Actions?exe=COMMON&order=voteCountDesc&p=1

2020/4/14
articleCard.readMore

好代码

什么才是好的代码? 每个写程序的人都会有这样的思考. 而其中很多人, 可能都会对 “优雅” 有执念. Dan Abramov 今年分享了一篇文章, Goodbye, Clean Code. 里面提到了几点: 重构并不总是好的. 在重构或重写代码时一定要与团队充分沟通. 在需求不稳定时, 重构会造成额外的负担. (尤为赞同) 不要对代码层面的抽象化与复用太过执着. 每位写程序的人可能都会经历这个阶段, 别怕. 这里一方面提到了团队的重要性, 加强沟通, 提升信任, 另一方面主要说的就是, 什么是干净的代码? 我们再延伸一下, 什么是好代码? 在我初学编程的时候, 我在思考如何写出优良的代码. 在我初学软件工程的时候, 我总会听到大家的提醒: 不要提前优化. 好像有一些矛盾, 工程在阻止我写出好代码吗? 让我们把 “团队” 也加入其中, 一起想想. 关于如何定义好代码, 如何让团队写出好代码, 是有许多点需要去平衡的: 功能完整性 团队能力 风格一致性 开发速度 代码执行效率 代码细节 代码复用 程序架构 这些点并不能单独拿来说, 其中一些点是相互制约的, 另一些点是相互促进的. 功能完整性是一切的前提. 但功能也分基础功能与扩展功能, 基础功能必做, 扩展功能则需要考虑开发成本可延后. 团队能力影响剩下的许多点. 如果团队能力弱, 则可以适当放宽风格一致性, 并且不要 使用过于复杂的程序架构. 风格一致性看上去没什么必要, 但对代码的观感与可读性, 是有很大提升的. 可能会 间接影响开发速度. 一般我们都会使用自动化的 format 工具去做. 开发速度与代码执行效率可以说在一定程度上是互斥的, 比如 Ruby 开发速度快, C 代码执行效率高. 一般来说都倾向于开发速度, 但没有绝对的, 如果花 10 分的时间可以 提升 30 分的执行效率, 这时间还是值得的. 代码执行效率可以很高, 但是有一个接受度阈值的, 一旦过了这个阈值, 大家都能接受, 那么再向上的提升就不那么必要的. 但随着程序负载增大等原因, 这个阈值可能会变. 关于代码细节, 可以说的方面很多. 一般, 只要不出错, 都可以接受, 但如果一个地方 使用生成可迭代对象的方法去做遍历, 那一定是可以继续优化的. 代码复用. 一般来说, 能复用的地方就复用. 但如何确定能复用? 我们不该在写第一个 例子的时候就开始对这个例子进行抽象以方便下一次复用, 而是要在下一次真正到来的 时候再开始抽象并复用. 甚至有时候当第二次, 第三次出现的时候我们都还不做复用, 比如 Dan Abramov 提到的, 需求还在变化中, 提前抽象会导致将来的功能变动难以实现, 从而导致更大的工作量. 程序架构. 架构似乎是最不重要的, 但也却是一开始就要确定的. 当然, 随着业务发展, 什么都可能会变, 架构也会随着变化. 架构是综合了上面所有的点, 总结出来的. 架构 要能保证功能的完全性, 符合团队能力, 可以实现自动化的风格一致性, 不会拖慢 开发速度, 在基础环节上能达到代码执行效率阈值, 同时尽可能约束代码细节, 避免 低级错误, 提供代码复用优化的可能. 关于如何平衡功能的实现与代码的优雅, 我的观点一直是: 代码的好是没有止境的, 只能无限接近于满分. 代码需要适应环境的变化, 尤其是高级语言. 基于以上两点, 好代码是慢慢进化的, 不断进化的, 不能一蹴而就. 先以最快速度完成基础功能, 然后不断优化. 开始时, 不使用框架或类库, 如果要用, 则使用基础的, 可插拔的. 随着项目的推进, 功能逐渐复杂, 产品目标逐渐清晰, 这时再考虑利用框架重构或重写. 在 Go Proverbs 中有这样一句话与 Dan Abramov 的文章异曲同工: A little copying is better than a little dependency. 现在, 就让我们停下来, 更多的思考, 然后进入对好代码执着的下一个阶段吧.

2020/4/14
articleCard.readMore

URL and cross-origin

:bulb: 下面的两个章节可能无关. URL 和 URI 有什么区别 根据 URL 的 wiki, URL 是一种特殊的 URI, 用来表示互联网资源. URL 的标准是什么 标准由 WHATWG 制定: https://url.spec.whatwg.org/ 标准是抽象的, 并且引用套引用, 就像一个包含无数小函数的程序, 需要梳理. 我们来看看 MDN 的文档吧, What is a URL? 在 UTF-8 的现在, 多语言不是问题, 而是大家的守则. 理论上任何语言都可以成为构成 URL 的 valid domain 和 percent-encoded byte. 但是我们倾向于使用这样的规则: 小写字母, 数字, 连字符. 谈谈跨域 - HTTP 203 这里 HTTP 203 指的是 Chrome 团队出品的一档谈话节目. HTTP 203 挺好的, 就是说话太快了, 来不及听. https://www.youtube.com/watch?v=vfAHa5GBLio 提到: 跨域请求问题来源于历史上 Cookies 会被一同发送. Access-Control-Allow-Origin 比 Origin 还有历史. 之所有会有 Origin 是因为历史上避免包含 - 的头被过滤. 但现在 Origin 会有更广泛的作用. 如果网页不使用 Cookies, 似乎就不是什么问题了. 在现在前端当中, Cookies 的功能已经可以完全被替代了. 但可以被取代, 不是会被取代.

2020/4/13
articleCard.readMore

Npm Fetchpackagemetadata Error

常见问题处理 npm fetchPackageMetaData error … Unexpected end of JSON input … 之前大多数项目都是使用 yarn, 但现在 yarn 正在切换到 berry, 有一些问题. 所以最近的新项目使用了 npm. 没想到, 这么多年过去, 依旧是坑. npm 的确是有效率问题的. 并且有一些低级问题没有进行处理. 效率问题比如依赖之间关系梳理的复杂, 效率低. 具体不展开了, 但实际使用感受已经足够说明问题. 是 Yarn 存在的意义. 同时也是 deno 想要避免的. 这里说一下在国内都可能遇到的问题: 网络原因导致包下载失败. 再次尝试仍然从缓存中拿失败的数据. 如果不清除缓存, 一直无法跳过失败数据. http fetch GET 304 https://registry.npmjs.org/cssnano-preset-default 982ms (from cache) silly fetchPackageMetaData error for cssnano-preset-default@^4.0.7 Unexpected end of JSON input while parsing near '...E1piZamJTcxPxUDG/h3FS' 其实这里可以增加一个简单的判断, 如果 JSON 化失败, 则判断为网络问题, 不再从缓存中拿数据. 无法单独清除某缓存, 比如 npm cache clean https://registry.npmjs.org/cssnano-preset-default. 缓存一致性检查 npm cache verify 奇慢. 无奈只好使用 npm cache clean --force 清除所有缓存. 想到清除所有缓存后, 随之而来的所有依赖被重新下载, 想想都头疼. 这真是一个太明显并且太严重的问题了. 网上许多 npm 包的 issues 都是因为 npm 的这一问题. 重新安装依赖中, 太慢了… 不过起码能用, 比代理会快点. 可是 Yarn berry 还是许多问题, 比如 https://github.com/yarnpkg/berry/issues/1149. 使用淘宝镜像吧: https://developer.aliyun.com/mirror/NPM 即便使用镜像, 还是挺慢的.

2020/4/10
articleCard.readMore

How To Reduce Cpu Consumption

如何减少CPU消耗 减少等待 减少IO量 SQL/index,使用合适的索引减少扫描的行数(需平衡索引的正收益和维护开销,空间换时间) 提升IO处理能力 加cache/加磁盘/SSD 减少计算 减少逻辑运算量 避免使用函数,将运算转移至易扩展的应用服务器中 如substr等字符运算,dateadd/datesub等日期运算,abs等数学函数 减少排序,利用索引取得有序数据或避免不必要排序 如union all代替 union,order by 索引字段等 禁止类型转换,使用合适类型并保证传入参数类型与数据库字段类型绝对一致 如数字用tiny/int/bigint等,必需转换的在传入数据库之前在应用中转好 简单类型,尽量避免复杂类型,降低由于复杂类型带来的附加运算。更小的数据类型占用更少的磁盘、内存、cpu缓存和cpu周期 减少逻辑IO量 index,优化索引,减少不必要的表扫描 如增加索引,调整组合索引字段顺序,去除选择性很差的索引字段等等 table,合理拆分,适度冗余 如将很少使用的大字段拆分到独立表,非常频繁的小字段冗余到“引用表” SQL,调整SQL写法,充分利用现有索引,避免不必要的扫描,排序及其他操作 如减少复杂join,减少order by,尽量union all,避免子查询等 数据类型,够用就好,减少不必要使用大字段 如tinyint够用就别总是int,int够用也别老bigint,date够用也别总是timestamp 减少query请求量(非数据库本身) 适当缓存,降低缓存数据粒度,对静态并被频繁请求的数据进行适当的缓存 如用户信息,商品信息等 优化实现,尽量去除不必要的重复请求 如禁止同一页面多次重复请求相同数据的问题,通过跨页面参数传递减少访问等 合理需求,评估需求产出比,对产出比极端底下的需求合理去除 升级cpu 低延迟(快速响应),需要更快的cpu(每个查询只能使用一个cpu) 高吞吐,同时运行很多查询语句,能从多个cpu处理查询中收益

2020/4/10
articleCard.readMore

Questions Philosophers Ponder

前言 通过了解哲学家们思考的问题能够帮助我们更加简单和通俗的认识到哲学是一门什么样的学科以及哲学家都在做些什么事情。从而对哲学产生一个相对准确和客观印象。 前苏格拉底时代(公元前700~公元前370) 前苏格拉底时代对应中国的春秋战国时期,老子,孔子的时代 泰勒斯通过观察水的形态变化提出水是构成世界的基本材料 毕达哥拉斯通过思考数学公式的确定性提出数字是宇宙的统治者 普罗塔哥拉提出人是万物的尺度,因为一个人看起来是正确的事情,另一个人可能会认为是错误的。 德谟克利特提出原子论世间是由原子和虚空组成的 前苏格拉底时代的哲学问题大部门集中在对自然哲学的思考,比如客观世界的原貌,万物的构成。 经典希腊时代(公元前470~公元前250) 经典希腊时代对应中国的战国时期 苏格拉底思考的问题是什么才是好的生活,生命的意义是什么。提出善是事物的本性,是万物追求的目标 柏拉图思考的问题是人类如何分辨出万物的正确的,完美的最本质的基本形态。比如我们看到不同品种不同形态不同颜色的猫都能分辨出来,那么必然所有的猫都有某种共同特征。这种由共同特征所组成的完美形态的猫才是我们应该去认识的。而现实世界只不过是这种完美形态的复制模型。 柏拉图提出一个“洞穴比喻”来说明。他让人们想象出一个洞穴,囚犯面向墙壁被绑在洞穴中,身后是一个火堆。囚犯和火堆之间不时有人走动或拿起不同物体,这些物体的影子反映在洞穴墙壁上。那么这些囚犯实际上并不能真正了解事物本身。柏拉图觉得人类感官所感知到的物质世界正如洞穴墙壁上的影子一样,是现实的缩影。 形而上学。形而上学是哲学的一个门类,研究世界的本质。比如超自然世界的本原,灵魂是否存在,自由意志是否存在等。通常对于形而上学的理解误区在于这一概念本身的形式,它不常与其他学科放在一起,我们会认为形而上学是一个概念而非学科。实际上它和数学,化学,物理学这些文字形式类似,当我们说某一问题是物理问题时,意味着这一问题属于物理学范畴。而当我们说某一问题是形而上的,也就意味着这一问题属于形而上学这门学科。 亚里士多德与柏拉图相反,柏拉图质疑自己的感官,而亚里士多德认为我们是通过感知来认识世界的。他认为现实世界中的物体并非物体完美形态的复制模型。我们应当通过研究个体来认识某一种类共有的本质。比如研究不同的猫得出猫共有的本质属性。对于公正,美德这些概念,我们只能通过观察他们在现实世界的各种不同呈现方式来逐渐修正对他们的了解和认识。 亚里士多德按照生物的特征对生物进行了归类。在这过程中制定了一套成系统的逻辑形式。期望运用逻辑推理出事实。例如,我们通过两个命题“所有人都会死”和“苏格拉底是人”可以推理出“苏格拉底会死”的结论。 伊壁鸠鲁认为人应当在短暂的人生中享乐。这种快乐并不是纯粹的身体感受到的世俗快乐,而是身体的没有痛苦和灵魂的不受干扰,是一种平静状态。。 芝诺认为宇宙有自己的规律,自然法则是宇宙的主宰。人应该遵循自然法则,追求各自与自然达成的和谐状态。 从苏格拉底开始,哲学家们开始关注对人本身的思考和探究。 受限于当时的知识水平,其中某些理论可能被现代人认为是简单的,不值一提的,甚至是错误的,但我们也不能否认他们在自己所处的年代开创出这些理论的革命性,和对人类文明后续发展的重要性。现代的很多领域中我们仍然能够清晰的看到这些理论所留下的印记。 参考 哲学百科 西方哲学史思维导图 1 西方哲学史思维导图 2 西方哲学史思维导图 3

2020/4/9
articleCard.readMore

道长在硅谷工作是怎样一种体验

概要 描述了故胤道长在 Uber, Amazon, Quora 的工作体验分享. 主人公是 CMU 毕业, 然后一路都是大厂经验, 主要从事 iOS 开发. 节目 来自播客 ggtalk 的一个系列节目. 讲工作经验的是其中一期. 也顺便讲了讲对行业, 职业规划, 生活的看法. https://poddtoppen.se/podcast/1440443653/ggtalk/%E9%81%93%E9%95%BF%E4%B8%89%E5%8D%81%E5%9C%A8%E7%A1%85%E8%B0%B7%E5%B7%A5%E4%BD%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E4%B8%80%E7%A7%8D%E4%BD%93%E9%AA%8C 主人公 故胤道长 soapyigu GitHub soapyigu: https://github.com/soapyigu 微博: https://www.weibo.com/soapyigu 听的感受 Uber (当时)是一家技术很激进的公司. Amazon (当时)的离职率很高, 许多新人. Quora (当时)是一家常青藤公司(戏谑). NETFLIX 一般不招实习生, 只招资深开发者. 选择工作时, 公司是一项重要参考, 同时具体的技术组和直接领导也很重要. 在美国不是只有湾区, Amazon, 微软总部都是在西雅图的. 在西雅图工作生活都挺舒适的. 美国大厂多数是现金 + 股票, NETFLIX 则全部是现金. 在美国如果想要更长远的职业发展, 要认真做事, 但同时也要会宣传自己. 作为软件工程师, 30 岁成为美国大厂 Senior 已经是很出色的了. 语言需要多听多讲, 但想要更进一步的沟通, 还需要了解当地的文化. 每一家公司都有自己的特点和生存之道, 无须苛责. 扩展阅读 访问 Quora 杨蕾: https://www.infoq.cn/article/9LhRWeXdYGh6mQQSiVZA 从 Google 离职加入 Quora. 带领 Quora 工程团队从 60 人增长为 120 人. 建立信任有助于团队接受批评和建议, 并进步.

2020/4/8
articleCard.readMore

空值合并运算符 nullish coalescing operator

:bulb: 目前 ?? 和 ??= 已经是 ECMAScript 正式标准了. ?? ?? 是空值合并运算符 nullish coalescing operator, 现在已经是正式标准了. 听名字就挺好理解的, 主要为了替代 || 的部分功能. ?? 与 || 的区别在于, || 判断真值, 而 ?? 只会判断非空值, 比如: null || 1 结果为 1, 0 || 1 结果也为 1. null ?? 1 结果为 1, 0 ?? 1 结果为 0. 空值合并运算符是 Finished Proposals(Stage 4). 将来大家都可以用到. 在浏览器中的支持情况已经很好了, 主流浏览器的最新版本都支持. 最新的 V8 已经支持, 但目前 Node.js 还不支持. ?? 是一个有用的语法糖, 推荐大家使用. ??= ??= 是逻辑空值赋值运算符, 也是 Finished Proposals(Stage 4). 最近 Logical Assignment Operators 提案到了 Stage 3. 以前没有关注过这一提案, 今天特意看了一下. 提案中说道, 在 ECMAScript 规范中, 有许多数学的赋值运算符, 但却没有逻辑的赋值运算符. 普通的赋值运算符就是 =. 数学的赋值运算符比如 += 是加法的赋值运算符, -= 是减法的赋值运算符. 所有的特殊赋值运算符目的都是为了简洁, 只是一种语法糖. 不过既然我们都有了数学的赋值运算符, 那就是认可了这种语法糖, 提案者据此提出了 逻辑的赋值运算符. 当然也是借鉴了其他语言, 如 Ruby. let opts = { foo: 'foo' }; // 传统写法 if (opts.foo === null || opts.foo === undefined) { opts.foo = 'bar'; } // 使用空值合并运算符的简写方式 // 注意:这种写法会总是触发赋值操作 opts.foo = opts.foo ?? 'bar'; // 使用括号来避免不必要的赋值 // 只有在 opts.foo 为 null 或 undefined 时才会执行赋值 opts.foo ?? (opts.foo = 'bar'); // 使用逻辑空值赋值运算符的最简写法 // 效果同上,更加简洁直观 opts.foo ??= 'bar';

2020/4/8
articleCard.readMore

那些年在网吧被盗的号

这里讲一个局域网网络攻击的方法,可能已经有点过时 知识点 ARP(地址解析协议) 定义:根据IP地址获取物理地址的一个TCP/IP协议。 实现过程:主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。 ARP欺骗 通过欺骗局域网内访问者PC的网关MAC地址,使访问者PC错以为攻击者更改后的MAC地址是网关的MAC,导致网络不通。此种攻击可让攻击者获取局域网上的数据包甚至可篡改数据包,且可让网上特定计算机或所有计算机无法正常连线。地址解析协议是建立在网络中各个主机互相信任的基础上的,局域网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存;由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。 场景模拟 网吧通常采用的是星型拓扑,所有主机连接到一台或者多台交换机,再由交换机连接到路由器。这样就有数量可观的主机都处在同一个局域网中,也是使用ARP欺骗攻击的理想场所。当这些主机中的某一台主机发起了ARP攻击,将自己伪装成网关,这时这台主机成了这个局域网内所有主机的“代理”。所有主机的网络请求都会通过这台主机转发,而这台伪装成网关的主机可以通过抓包工具轻松的获取他们请求,这其中就包括了一些账号的登录信息。

2020/4/8
articleCard.readMore

Insert Into Select

Insert into select语句用法提示 业务场景 将表A的数据迁移到表B中去做一个备份。本想通过程序先查询查出来然后批量插入,但觉得这样有点慢,需要耗费大量的网络I/O,查资料后决定采取sql insert into select语句实现,这样就可以避免使用网络I/O,直接使用SQL依靠数据库I/O完成。 执行解析 在默认的事务隔离级别下:insert into B select * from A 加锁规则是:B表锁,A逐步锁(扫描一个锁一个)。 通过观察迁移sql的执行情况你会发现A是全表扫描,也就意味着在执行insert into select from 语句时,mysql会从上到下扫描A内的记录并且加锁,这样一来就和直接锁表是一样了。 由于查询条件会导致A全表扫描,那么什么能避免全表扫描呢,给查询条件字段添加一个索引就可以了,由于走索引查询,就不会出现扫描全表的情况而锁表了,只会锁定符合条件的记录。 总结 使用insert into tableB select * from tableA语句时,一定要确保tableA后面的where,order或者其他条件,都需要有对应的索引,来避免出现tableA全部记录被锁定的情况。

2020/4/7
articleCard.readMore

司徒正美, 健康

概要 网传, 司徒正美离世, 可能因为颈椎病, 但具体情况不明. 因为想以 React 语法开发微信小程序, 了解过 anu 和 nanachi. 纪念一下他, 也提醒大家关注常见疾病颈椎病, 关注自身健康. 司徒正美其人 网名: 司徒正美 / RubyLouvre 钟钦成 从业多年, 出过书, 以前在去哪儿, 现在应该已经从 qunar.com 离职, 应该是业内一位人物. 主要在国内的社群活动, 比如博客在 cnblogs. 在知乎也有一些回答. 也活跃在 GitHub. 有 Twitter, 但不怎么用. 一位坚持写博客 10 年的人, 值得敬佩. 工作经历可以在 LinkedIn 看到. 2013 年来北京, 在去哪儿工作多年. 最近在刷题, 可能是疫情原因, 也可能是离职后有时间了. 颈椎病 首先, 推荐大家看默沙东关于颈椎病的介绍. 其次, 默沙东有一篇文章谈到了对任何疾病的预防手段. 简单列举一下就是: 系好安全带 饮食健康 (低热量, 低饱和脂肪, 低反式脂肪酸) 身体锻炼 (规律, 足量) 涂防晒霜 不抽烟 免疫接种 定期体检 希望大家健康.

2020/4/4
articleCard.readMore

DynamoDB 心得分享

:warning: 本文可能已过时 简介 DynamoDB 是一种完全托管的 NoSQL 数据库服务。 DynamoDB 的核心 在 DynamoDB 中核心组件是表、项目和属性。 表是项目的集合。 项目是属性的集合。 DynamoDB 使用主键来标识表中的每个项目,还提供了二级索引来提供更大的查询灵活性, 还可以使用 DynamoDB 流来捕获 DynamoDB 表中的数据修改事件。 DynamoDB的优点 性能稳定。为了保证高性能,DynamoDB 采用固态硬盘(SSD)进行存储,对于一般的请求, DynamoDB 可以在 10 毫秒内完成,而且请求速度不会因为数据量增加而减慢。 读/写流量限制预设。用户可以随时通过控制台或者API更改数据库的读/写流量的限制。 自动扩容。DynamoDB 不会对用户的数据规模大小做任何限制,后台会默默地把用户的 数据分不到各个机器上去。 强一致性。用户可以通过参数指定要读的数据是否需要一致性。 完全分布式,无中心化结构。一个表上的数据可以分布在几百台机器上。 DynamoDB 和 SimpleDB 的区别 DynamoDB 与 SimpleDB 都是 AWS 上的 NoSQL 数据库,DynamoDB 优于 SimpleDB。 SimpleDB 有单表限制。SimpleDB也有类似于Table的东西叫做Domain,每个 Domain 最多只能保存10GB的数据,而 DynamoDB 并没有单表存储的任何限制。 SimpleDB 默认为表内所有属性创建索引,这就导致 SimpleDB 性能不稳定。 SimpleDB 为最终一致性模型,DynamoDB 可以选择弱一致性或者强一致性。

2020/4/1
articleCard.readMore

从物理层面了解数据传输

知识点 OSI七层模型 OSI七层模型(从上至下)分为:应用层,表示层,会话层,传输层,网络层,数据链路层, 物理层. 其中上三层(应用层,表示层,会话层)统称为应用层,在这里不做考虑。 网络层 网络层通过ip进行寻址,在这一层的网络设备主要以路由器为主。 路由器的特点是用来连接不同的网络。 数据链路层 数据链路层主要通过mac进行寻址,这一层的网络设备主要以交换机(二层交换机)为主。 交换机的特点是所有连接交换机的主机都必须处在同一个网段中。 交换机与路由器的区别 交换机的接口较多,路由器的接口较少。(一般情况下)路由器的每个接口都代表一个不同的网段, 交换机的每接口必须处在同一个网段中。 ARP协议 ARP协议属于网络层协议,将网络地址(ip地址)解析为硬件地址(mac地址)。 当局域网(192.168.1.0网段)内的两台主机A、B进行通信时且A只知道B的网络地址不知道B 的硬件地址的情况下A如何将数据发送给B。 A先查找自身的ARP缓存列表,查找B无果。会向192.168.1.255(网络地址)发送一条 携带目标ip地址的ARP广播请求并设定一个过期时间, 该网段内的所有主机会收到该条广播,并且跟自身ip地址进行对比,如果该条广播的目标ip 地址与自身的ip地址不相符则将这条请求抛弃, 如果相符则响应这条广播。主机A在超时时间之内收到响应,则将主机B的硬件地址和缓存 地址保存在自己的ARP缓存列表中以备下次进行数据传输。 如果超过过期时间任然没有接收到响应,则判定主机B不在当前局域网内。 数据封装 这里主要介绍网络层和数据链路层的封装。 网络层对传输层的数据报进行封装,封装成为数据包,包的头部保存ip地址等信息。 ip地址为192.168.1.2的主机A要给ip地址为10.0.0.212的主机B发送一条消息数据怎样传输的 主机A将数据层层封装为数据帧发送出去,由于目标ip不在当前网段,主机A会将数据帧直接发送给网关。 路由器在接收到数据以后就将数据帧解封到三层的数据包, 并查询自身的路由表将数据分组转发到对应的接口,目标数据发送到目标局域网, 进行查找目标主机(通过arp协议进行辅助查找),目标数据在封装成帧发送给主机B。

2020/3/31
articleCard.readMore

JavaScript ES6 简单数组去重

Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。 Set 本身是一个构造函数,用来生成 Set 数据结构。 const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]; console.log([...new Set(numbers)]) 另外,NaN和undefined都可以被存储在Set 中, NaN之间被视为相同的值(NaN被认为是相同的,尽管 NaN !== NaN)。 Set 简单扩展应用 用Set实现并集,交集, 差集 const a = new Set([1, 2, 3]); const b = new Set([2, 3, 4]); // 并集 const union = [...new Set([...a, ...b])]; // ==> [1, 2, 3, 4]; // 交集 const intersect = [...new Set([...a].filter(v => b.has(v)))]; // ==> [2, 3]; // 差集 const difference = [...new Set([...a].filter(v => !b.has(v)))]; // ==> [1]; 扩展阅读: https://stackoverflow.com/a/9229821/4124389

2020/3/30
articleCard.readMore

Node.js 生态中的流行包 request 正式被弃用

在 2019 年 3 月份, 作者就创建了相关 issue 讨论逐步让 request 进入历史. 最近, 作者正式宣布弃用该包. 关于弃用的原因, 主要是历史比较久远, 核心代码已经跟不上 Node.js 的发展. 我倾向标准库强大的语言. Go 从设计之初就拥有强大的标准库, Node.js 则是随着 ECMAScript 的进步, 逐渐通过语法来完善与丰富自己. 替代 关于 request 的替代品可以参考这个 issue. 经验 其实我们并没有使用过 request, 在 Node.js 中只是用 node-fetch 和 axios. 在最初进入 Node.js 的时候, 我们关注到了 request, 但语法并没有打动我们, 所以我们转向了 node-fetch. 因为我们同时会写前后端, 在前端标准化的 fetch 让我们能尽快入手. 但正是由于我们前后端同时在写, 我们发现 node-fetch 的语法并不完全等同 fetch. 这让我们更容易因为忽略了差异项而出错. 之后我们再次寻找替代品, 发现了 r2. r2 代码的体积很小, 我们就看看源代码, 发现只是简单调用了 node-fetch. 在最近的项目中, 我们才开始用当时还流行的 axios. 我不太喜欢 axios 的语法, 有些过度了. 但基于流行原则我们还是在继续使用. 现在来看, request 作者的新包 bent 才是我们在 Node.js 中更应该做的选择. bent bent 是一个同时支持浏览器与 Node.js 的 HTTP client. 在 Node.js 环境中, 进行了 Promise 化和流的支持. 在浏览器端, 对 fetch 进行了简单封装以符合 bent 的 API. 源代码很小, 依赖也不多. API 简洁实用. 是我们理想的选择. 但在浏览器端, bent 的封装对我们帮助不大, 我们还是会选择 fetch 然后自己封装.

2020/3/29
articleCard.readMore

PHP, Go, Node.js 框架性能综合对比

数据来源 https://www.techempower.com/benchmarks/#section=data-r18&hw=cl&test=query 分析的指标 JSON serialization 序列化响应 Plaintext 简单响应 Single query 单行查询 Multiple queries 多行查询 Data updates 数据更新 分析的对象 考虑的几种方案: Node.js (函数计算) Go (单机部署) 这里的单机部署并非只有一台机器, 只是区别于 网关 + 函数计算 的方式. 具体应用: echo (Go) go-pgx-easyjson nodejs-postgres (ORM) php (nginx) php-pgsql-raw (nginx) lumen (nginx, ORM, MySQL) 没有看到 PHP + PostgreSQL 的组合. 与 Golang 组合的基本都是 PostgreSQL. 分析概览 Rust 非常快, 甚至超过 C 与 C++. Java 也很快, 但我不知道这些框架流行程度. 原生 PHP 整体并不慢, 但结合框架就慢了. Go 数据请求的处理性能比 Node.js 更快. 虽然显示 Go 的性能是 Node.js 的 3 倍以上, 但慢一部分出在 ORM 上. 原生写 Go 与使用 echo 性能基本一致. 分析细节 JSON serialization 序列化响应 不涉及具体数据库. Framework Performance echo 32.8% go 31.9% go-pgx-easyjson 31.4% nodejs 23.6% php 12.5% lumen 1.1% Plaintext 简单响应 不涉及具体数据库. Framework Performance fasthttp 65.3% nodejs 7.9% go 6.4% echo 5.2% lumen 0.1% Go 在这个环节比 Node.js 慢有点出乎意料, 但换用 fasthttp 第三方库还是一骑绝尘的. 一般来说, 这种简单响应的应用场景主要是 HTTP OPTIONS method. 但在函数计算中, 可以由网关响应该请求以节省运行开支. Single query 单行查询 Framework Performance echo 46.2% go-pgx-easyjson 43.1% nodejs-postgres 13.8% php-pgsql-raw 13.8% lumen 1.5% Multiple queries 多行查询 Framework Performance go-pgx-easyjson 47.8% echo 44.3% php-pgsql-raw 30.0% nodejs-postgres 14.4% lumen 8.1% Data updates 数据更新 Framework Performance go-pgx-easyjson 35.4% echo 31.8% php-pgsql-raw 20.4% nodejs-postgres 8.2% lumen 6.9% 总结 如果单机部署, 使用 echo 作为基础是一个好的方案, 良好的社区支持, 简单易用. 如果使用了 echo, 就不考虑 fasthttp 了. 虽然在 v2 中支持过 fasthttp, 但在 https://github.com/labstack/echo/issues/665 中, echo 作者解释了为什么放弃, 保持简单及社区兼容, 也就是尽量使用标准库. 如果函数计算, 那么 Node.js 也是不错的选择, 可以接受的性能, 与前端通用的语法. 从以上的性能测试来看, PHP 本身的性能问题不大, 但标准库太过老旧, 必须使用框架才能提高开发效率. 但普通框架导致性能极具下降. 并且因为历史原因, PHP 配合 Nginx 才能高效完成网络任务, 单机部署步骤更多.

2020/3/28
articleCard.readMore

国内部分地区用户遭到中间人攻击

根据 V2EX 社区帖子, GitHub 在国内遭受大规模中间人攻击. 什么是中间人攻击? 如何防范? 什么是中间人 在用户与服务器之间的任何层, 都可以称为中间人. 包括但不仅限于: 本机设备的恶意软件 本地路由器 各级电信运营商 国际出口 攻击目的 阻断沟通. 伪造身份. 大多数中间人攻击都是为了伪造身份, 比如攻击者不是银行, 伪装成银行与客户进行沟通 以套取密码. 如何进行 直接劫持并替换数据包. 通过 DNS spoofing. 阻断数据包. 什么是 DNS spoofing? https://en.wikipedia.org/wiki/DNS_spoofing https://www.cloudflare.com/learning/dns/dns-cache-poisoning/ 我们经常遇到这种 DNS 攻击, 如何识别与防范以后单独写一下. 如何防范 本地客户端对等加密. 传输层加密. 本地客户端对等加密 比较简单, 应用范围有限, 目的是为了防止中间人直接获取有效信息, 提高难度. 什么是本地客户端对等加密? 比如本地向服务器传输 123 这个字符串, 但不直接传输, 而是与服务器端沟通好, 以 ! 代表 1, @ 代表 2, # 代表 3, 实际传输 !@#. 这样, 如果中间人不知道二者的加解密方法, 则无法获取有效信息. 但这种方法有很大局限性, 比如如何保证中间人不知情? 加解密方法不能通过中间人网络. 前期沟通成本高. 为了解决上述问题, 更常用的是传输层加密, 比如 HTTP over TLS, 也就是我们说的 HTTPS. 有人会问, TLS 与 SSL 是什么关系? 调侃地说: 就像 ECMAScript 与 JavaScript 的关系. 中文维基百科上有一句话: “IETF将SSL进行标准化,1999年公布第一版TLS标准文件”. TLS 是如何防范伪造身份为目的的中间人攻击呢? 客户端发给服务器端本地可用的加密方法. 服务器端看一下自己能使用哪一种, 然后告诉客户端用什么方法加密和公钥证书. 客户端此时判断服务器的公钥证书是否可信. 证书是由第三方发放的, 如果客户端认为 该第三方可信, 即证书颁发者在自己的可信根内, 则认为服务器可信. 客户端与服务器端建立有效连接. 如果想进一步知道, 客户端与服务器端如何建立有效连接, 服务器如何信任客户端, 请看: 客户端根据公钥加密一个随机数据, 发给服务器端. 服务器端解密后得到这个随机数据. 此时双方都获得了这个随机数据, 然后双方利用这个随机数据再次对等加密收发数据. 详细的 TLS 细节请看: https://en.wikipedia.org/wiki/Transport_Layer_Security#Protocol_details 相关新闻 https://v2ex.com/t/656394 https://www.cnbeta.com/articles/tech/960295.htm

2020/3/27
articleCard.readMore

云计算实例可以有多个 IP 吗

对于运维, 什么是云服务? 云服务有什么好处? 云服务提供商有区别吗? 云服务是为了节省运维开支的, 中小公司尽可能用云. 今天有人问我, 一台服务器可以有多个 IP 吗? 我回复说: 云服务器计算,储存,网络都是分开的。一个计算可以有多个 IP。 就像我们电脑可以有多个网卡,可以连接不同猫获得多个 IP。只不过云上是虚拟的。 但以上为理论, 我们没有类似需求, 没有实践过. 出于谨慎, 我实操了一下: AWS 中国支持一个 EC2 实例多私网 IP 及多公网 IP. (仅限操作台) 阿里云 VPC 不支持为一个 ECS 实例提供多个公网 IP. (仅限操作台) 但需要注意, 我仅在 Web 操作台上进行了操作, 没有使用 CLI 工具. 不排除阿里云在 API 层面提供更多功能的可能性. 因为以我们的经验, 在安全组设置的时候, 有些不太安全的 设置在操作台上被禁止, 但是在 API 层面是允许的.

2020/3/26
articleCard.readMore

VS Code, Eclipse Theia, Remote Development

Eclipse Theia 项目: https://github.com/eclipse-theia/theia 说到前后分离可以运行在远端的编辑器甚至工作台, 我第一个想到的就是 VS Code. 如果你在用远程工作台, 不要认为这一定是 VS Code, 即便 UI 看上去很像. 因为这也有可能是: Theia. Theia 是一个开源项目, 而不是开箱即用的编辑器. 想要试试看可以通过 Gitpod. Eclipse Theia 与 VS Code 的区别 Theia 官网说, 自己与 VS Code 最大的不同有三点: 更加模块化与可定制. 专为桌面和远程设计. 独立基金会. 不过, 从使用者角度看就一点: VS Code 是开箱即用的工具. Theia 是搭建自有编辑器的基础. 做普通用户, 我们在做远程开发的时候, 还是会选择 VS Code. 但很感谢 Theia 对开源社区的贡献, 我觉得正是有了 Theia 这样的项目, 才鞭策 VS Code 做得更好. Remote Development 为什么要用 Remote Development? 经常有远程办公不来办公室的需求(大多数情况不是加班), 如果不是一台笔记本带来带去的, 就会遇到需要在不同机器上安装开发依赖, 拉取项目, 系统配置等一系列问题, 都要做一遍, 很耗时. 如何结合远程服务器来使用 VS Code? 一般来说, 一定会有服务器端与客户端. VS Code 就是我们的客户端了. 那服务器端呢? 怎么安装? 我们无需特别地在服务器端安装什么, 这一些都会在 VS Code 这个客户端中帮我们自动设置好. 当然, SSH 还是需要的. 我们只需要在 VS Code 上安装 https://aka.ms/VSCodeRemoteExtensionPack 插件. VS Code 这个插件通过 SSH 在服务器上自动安装了服务器端依赖. 前置步骤: 本地安装 VS Code. VS Code 安装 Remote Development 扩展. 步骤如下: 打开 VS Code. 左侧功能导航栏选择 Remote Explorer 图标. 选择 SSH Targets. 点加号创建一个 SSH. 使用 SSH 登录到服务器, VS Code 会自动安装服务器需要的东西. 结束, 就像本地一样使用远程机器进行开发吧.

2020/3/25
articleCard.readMore