- passive event listeners
passive event listeners 是一种新兴的web标准,Chrome 51中提供的新功能为滚动性能提供了巨大的潜在提升。Chrome Release Notes.
背景:所有的现代浏览器都有一个滚动功能的线程,可以保证即使在运行耗时的js代码时滚动也能够平滑进行,但这种优化部分因需要等待任何touchstart 和 touchmove处理程序的结果而失败,因为这些交互可能会通过调用preventDefault()
事件来完全阻止滚动。
于是有了 {passive: true}
通过将touch
或wheel
事件监听标记为 passive
,开发人员承诺处理程序不会调用 preventDefault
来禁用滚动。这使浏览器可以立即响应滚动,而无需等待js的执行,从而确保为用户提供可靠流畅的滚动体验。
-
关于系统设计
- 关于分层
分层一般是基于模块功能来分层,有时候分层不清晰可能是有哪些模块,各模块间的功能,整个功能流程不是很清楚。
有时候两个模块间的交互复杂度增加,可以考虑构建一个中间层。 这样可以保持两个模块不会杂糅相关度不是很高的处理逻辑,功能逻辑更纯粹,保持边界清晰,降低模块本身的复杂度。
- 关于编程思维
仔细想来,虽然从事开发工作很久了,但是编程上还是很没有章法,架构设计能力较弱,多年来都是凭借以前热血和几分小聪明存活。
今日份反思:
拿到一个需求,分析该需求需要支持那些场景,为了支持这些场景它需要具备哪些功能,思考怎样实现这些功能,根据功能做模块划分,对这些模块进行分析,做逻辑抽象(也就是分层),然后整个需求实现的大致框架就心中有数了,开始产出技术方案。 技术方案产出后,按照技术方案的设想去实施,实施过程中可能会遇到没考虑到的场景,或者发现之前的设计不能很好的cover,调整设计,增加分层或者调整已有的分层,然后修改技术方案。 不断的经历上述过程,会慢慢的沉淀出一些业务通用的设计思路,这样下次再做技术方案的时候就不会很迷茫。脑子理清楚,而后出设计,实践后总结。
ShadowRealm API
一个进入 statge3
的新的 JavaScript
提案,用于创建一个独立的JavaScript运行环境,里面有独立的变量作用域。
数据结构:
ts
declare class ShadowRealm {
constructor();
// 同步执行字符串,类似eval()
evaluate(sourceText: string): PrimitiveValueOrCallable;
// 返回一个Promise对象,异步执行代码字符串
importValue(specifier: string, bindingName: string): Promise<PrimitiveValueOrCallable>;
}
使用场景:
- 在Web IDE 或 Web绘图应用程序中运行插件等第三方代码; 这种方式比iframe的实现更简单、灵活度更高,占用内存更少、代码的安全性更高。
- 用 ShadowRealms 中创建编程环境,运行用户代码,如codepen,codesandbox;
- 服务器可以在 ShadowRealms 运行第三方代码,防止第三方代码出错打挂主环境;
- 网页抓取和网页应用测试可以在ShadowRealms中运行;
补充:Node.js
的vm
模块与ShadowRealm API
类似,但具有更多功能,缓存Javascript 引擎,拦截import()
等等。
- 关于状态管理
做状态管理的核心就是监听数据的变化,监听数据的变化有两种方式:
- 提供api来修改,内部做联动处理(React的setState)
- 对对象做一层代理,set的时候做联动处理,同时get时收集所有依赖。(vue,mobx的响应式数据)
- 需求/调研
关于需求调研,我还是很急躁,急急忙忙开始技术方案评审、开发、排期的话,就会导致整个开发过程很被动。
比较好的方式,前期对于自己做的需求,以及需求的各个功能依赖有比较充分的了解(不过这在很多功能依赖方都没有文档的情况下很难做到),然后写一个符合需求的简版的demo,对可能出现的阻塞点和解决方案心里有一个预期,把图纸画好,照着图纸开发,从而更好的掌控整个开发进度。
- 功能/需求拆解
对功能需求的有效拆解,功能模块详细具体,粒度合适,不会太过细化,也不会忽略一些关键点,才能够更好的把控整个开发进度,评估可能出现的风险点。
- 工具方法收敛思路
收敛-内部集中分发给各个具体的util处理,保证对外暴露的接口的统一,降低该方法使用的心智负担。
- 关于「自顶向下」和「自底向上」
自顶向下:
程序设计时,先考虑整体,后考虑细节。先考虑全局目标,后考虑局部目标。不要一开始就过多追求总多的细节,先从最上层总目标开始设计,逐步使问题具体化。
模块化设计:一个复杂的问题,肯定是有若干稍简单的问题构成。模块化是把程序要解决的总目标拆解为子目标,再进一步细化分解为具体的小目标,把每一个小目标称为一个模块。
自底向上:
自底向上的设计简单来说就是先完成细节功能,每个细节功能抽象成一个运算符,然后将这些完成的细节功能组装到整体的架构中。
自动化的设计是不是就应该采用自底向上的设计思路,把每个需要的细节功能做抽象,使得配置规则的人可以任意组装,对于不支持的功能制造新的抽象?
- eval 和 new Function的区别
eval 和 new Function都可以解析执行一段传入的字符串。但有以下不同的地方:
- eval中的代码是当前作用域,它可以访问当前函数中的局部变量和全局变量。new Function中的代码执行的作用域是全局作用域,不论它在哪个地方被调用,可访问的都是全局变量;
- eval接收函数作为字符串时需要"("和")"作为前缀和后缀,new Function不需要,new Function可以接收N个参数,最后一个参数作为函数体;
- eval不容易调试,用chromeDev等调试工具无法打断点调试;
- 性能问题,eval通常比其他替代方法更慢,因为他必须调用js解释器,而其他结构则可被现代js引擎优化;
- eval存在安全问题,因为可访问局部作用域的变量,其内部逻辑不可预测性很强,可能导致XSS攻击;
- 乐观更新与保守更新
- 乐观更新(Optimistic Update): 乐观更新:如果有编辑等改动,先更新前端页面,再像服务端发送请求,如果请求成功则结束操作,无需额外处理,若请求失败,则页面回滚到先前状态; 这样更新方式的优点是响应及时,缺点就是低概率的请求失败回滚的体验不太好。
- 保守更新(Perssimistic Update): 保守更新:如果有编辑等改动,向服务端发送请求,等收到回复请求后再响应用户操作,在此之前用户都需要处于等待状态。 这样做的缺点是会使页面有比较大的延时感,优点是最终呈现的结果是可信赖、稳定可靠的。
- 正交的概念
编程上的正交,从数学上引进这个词,用于表示相互独立,相互间不可替代,并且可以组合起来实现其他功能。比如if和for语言是正交的,但for和while与句的功能是有重叠的。逻辑运算not、and也是正交的,其他复杂的逻辑运算都可以用这三种基本运算叠加起来。 编程语言经常定义一组正交语法特性,相互间不可替代,组合起来可以实现其他功能。为了更方便使用,在基础特性之上,再添加一些额外特性。这些非基本的额外特性,成为语法糖。语法糖对语言的功能没有太大影响,只是有了,代码写起来更方便些。
- 引入外部字体,因等待字体文件的加载而产生文字不可见问题的一些解决方案
- 临时显示系统字体:添加
font-display: swap;
到自定义字体的style中,在自定义字体加载好之前显示系统字体; - 预加载网页字体:用
<link rel="preload" as="font" >
更早的获取字体文件。
- 总结写技术文章的几个步骤,引导自己学习并践行:
- 学习优秀的人写的东西,看看他们的理解;
- 带着自己的疑问,和目前接收到的理解去读源码;
- 读完之后,按照自己最终的理解绘制相关逻辑的流程图;
- 针对关键功能模块做拆解和源码解读;
- 总结相关功能的实现机制,以及给我带来的启发和思考;
- 关于团队中被高频讨论的去底座;
去底座不是完全失去对底座(数据)的访问能力,而是设计一个标准化的API来支持按需访问底座(数据)的能力。