Mindblown: a blog about philosophy.

  • three.js系列之网格模型mesh

    mesh由两部分组成,geometry几何体和material材质 Geometry 我们知道几何体都是有点构成的,在三维场景中,点的坐标由x,y,z三个值组成,所以要绘制一个点,需要提供一个有三个数值组成的坐标{x, y, z},以此类推,三角形则需要三组坐标{x1, y1, z1, x2, y2, z2, x3, y3, z3},正方形需要四组…. threejs为我们封装好了基本的几何图形,如BoxGeometry, CircleGeometry, PlaneGeometry, SphereGeometry等常用图形,我们只需要提供组成图形的基本信息如长、宽、高、半径等等就可构建出图形 另外threejs也提供了一个可供我们自己创建图形的BufferGeometry,我们可以提供点的坐标来自由组合图形 以上的六个点可以组成一个自定义图形 Material 接下来轮到材质了,材质控制的是物体的外观,常见的材质包括 物体的移动 控制物体的移动,我们通常用到四个属性 移动物体示例: 动画效果 这里需要用到的是tween这个利器了,实现方法

  • three.js系列基础

    之所以用这个题目是觉得threejs无论学了多久永远都是学了忘,忘了再学,在项目中没有实践永远都是隔岸观火,没办法深入进去,这次再挣扎一下,做个学习笔记吧,希望能加深些印象。 本系列笔记是跟随Bruno Simons大佬边学习边做的笔记 入门开始,先来些枯燥的原理做开胃菜吧😈 说起threejs,是web领域最负盛名的3d引擎框架,和其他的如babylon.js不同,他们主打的是做游戏,因此有非常丰富的游戏常用接口,而threejs则更加底层,实现的是帮助我们打通和webGL连接的通道,毕竟webgl实在太难搞了,写一个小三角行都要好几十行代码。 threejs实际上就是封装好了接口,让我们可以直接调用接口实现画图。 提到webgl就不得不说到最新的webgpu概念了,据业界大佬传闻webgpu标准很快就会确定了,那时我们web3d很可能也有大展拳脚的机会了,哈哈哈哈哈….. 话不多说,回归正题。 在threejs中,创建一个3d的场景需要以下几大要素: 除此之外还有一些非必要的元素,control — 控制器, light — 光源 等等可以给场景添加额外的功能

  • 浅析Webpack工作原理

    webpack可以看成一个项目打包机,他会先将浏览器不能识别的格式如sass, less等转换成浏览器可识别的css共浏览器使用,在3.0之后webpack还加入了优化项目的责任 常用的基本配置: 常用配置: Tree Shaking 在ES6的import中,当我们引入一整个文件时很可能真正需要的只是其中的几个方法,那么有没有办法去除冗余的代码吗? 答案就是tree shaking 首先明确一下tree-shaking是不支持动态导入的(require),只能是用静态导入的import 他的原理是先标记出模块导出值中哪些没有被用过,再删掉这些没被用过的导出语句

  • 深入理解React – 6 – 并发渲染

    React的 Concurrent Renderer 并发渲染器 React18之后引入了并发渲染器,concurrent renderer,根节点使用createRoot, 他主要有以下两个特点 时间切片 因为浏览器16.6ms刷新一次,如果单个任务执行时间超过16.6ms就会造成卡顿,因此并发模式引入了一个shouldYield的判断,会每隔5ms打断一次,这就是时间切片。打断之后会重新恢复调度渲染,通过这种打断和恢复实现了并发。 另外scheduler可以通过优先级来对任务进行排序,这样就实现了高优先级先处理。 每次的setState渲染都是有scheduler维护的,它有一个任务队列,上个任务执行完毕再执行下一个,被打断的任务会被添加到任务队列里。 优先级调度 Schedular处理事件的优先级是按照如下排列的 ImmediatePriority是指离散型的事件,如click, keydown, input等UserBlockingPriority指连续性的事件,如scroll, drag, mouseOver等 而React处理的优先级采用的是Lane。 React是使用二进制来存储这个lane优先级的

  • 深入理解React – 5 – Fiber

    React Fiber架构 React在16.3之后引入了Fiber架构。 我们知道生命周期主要有三个阶段,即渲染阶段,调和阶段,提交阶段。 在引入fiber结构之前,React的diff算法是采用深度优先遍历(DFS)的算法,是一个递归的过程,当DOM结构复杂时调和需要的时间过长,会导致js主线程被长时间占用,因此会出现卡顿,交互无反应等问题。 为了解决这个问题才引入了fiber架构。 就是在调和阶段将原来的栈调和(stack reconcilation) 改为新的fiber调和。 调和和diff算法有什么关联呢? 调和就是指将实际DOM按照虚拟DOM渲染成一致的过程, 而diff算法只是这个过程中的一个步骤,也就是说调和是包含diff算法的。 fiber架构的diff算法主要从以下几点进行了突破 React Fiber架构有哪些优点呢? 三大优点,可中断,可恢复,优先级 fiber中增加了一个scheduler 详细说下可中断和可恢复,在插入一个优先级更高的任务时,传统树需要把后边所有未处理的任务保存起来,这会带来很大的开销,而fiber树只需要把当前节点记录在一个变量里就可以了,下次更新可以按照逻辑先遍历自己,再child, 再siblings 优先级 child -> siblings -> return 这里有两个处理方式,从beginWork开始,向下面的children寻找是调用beginWork,当没有子节点时,调用completeUnitOfWork回到兄弟节点 Fiber树 Fiber树和传统树有很大的不同,父节点只和他的第一个子节点相连接,而第一个子节点和后边的兄弟节点相连接,每个孩子都有一个指向父亲节点的指针,这样构成了一个单向链表的结构 Fiber树有新旧两个树,即current tree和workInProgress tree current tree 存储当前页面中每个组件状态 更新节点时,根据current tree和一些修改过的参数形成 workInProgress tree。 最终React将workInProgress tree渲染到页面,再把他复制成current tree。 在构建current树时,是边构建边diffing的,如果构建到一半被打断,那么current树还在,如果构建完成了则删除掉current树,workInProgress树成为新的current树 所以说旧的diff算法是对比虚拟DOM和真实DOM的区别,fiber的diff算法是对比两棵树的区别

  • 深入理解React – 4 – Hooks

    React Hooks 我们知道从React16以来React官方团队引入了新的组件书写方式,即Function Components,从Class Components 过渡到Function Components, 从两者兼容,到鼓励大家使用Function Components这中间发生了什么呢? 我们一起来看一下吧。 Question: 为什么要从Class Components过渡到Function Components呢? 第一点就是组件的复用更容易了,React在引入Function Component的同时也引入了React Hooks这一概念,我们可以通过编写自定义Hook 来代替原来的HOC或者Render Props。 自定义hooks更加易于理解,也对我们研发人员更友好 第二点class components的this指向问题,在class组件中,一些改变DOM的操作,虽然props是不变的,但是this的指向是有可能发生改变的,如果this上的数据被修改可能造成意想不到的变化,例如用setTimeout延迟渲染,等待的过程中就有可能打破this.props和渲染之间的关联。 而在函数组件中每一次调用都是传入参数做新的调用,不会影响上一次操作对DOM的捕获 那么我们再详细聊一下React Hooks吧 常用的React Hooks包括useEffect, useState, useRef, useCallback, useMemo等 useEffect 因为在函数组件中我们不能再使用生命周期的方法了,因此React团队引入了useEffect用来处理组件的副作用(side effects)。 说到副作用,一般认为脱离了React作用范围的功能都叫做side effects, 例如webStorage的操作, fetch data等。 常用的生命周期componentDidMount, componentDidUpdate, componentWillUnmount都可以用useEffect代替,但官方并不鼓励我们用useEffect时去思考代替原来的生命周期,因为useEffect是一种完全不同的设计模式,他的出现就是为了处理副作用。 useState 用来在函数组件中设置和更新变量 useRef useRef用来操作DOM,需要先做好绑定操作,常用来制作动画效果 useCallback (性能优化) React在重新渲染组件时需要重新渲染组件和方法,因此在复杂应用需要同时处理上百个组件的情况就会造成很大的开销。因为方法造成的开销更大,因此React引入了useCallback这一个hook,useCallback会缓存方法,注意并不是缓存方法执行的结果,他会在参数没有变化时返回原有的方法。他和useEffect一样,需要指定一个以来的数组,在数组没有变化时不再重新初始化这个方法。dependency对比是用Object.is做对比的(==会转换对比的类型;===对比+0和-0会返回true,Object.is返回false; ===对比两个NaN会返回false, Object.is会返回true) useMemo(性能优化) 同样是性能优化的常用手段,useMemo是存储计算的结果,只有在依赖数组发生变化时才会重新计算 React Hooks的使用原则…

  • 深入理解React – 3

    用过Vue和React的小伙伴都知道,两个框架一个很重要的区别就是数据的传递。在Vue中数据是双向绑定的,而在React中的数据是严格单向传递的,今天我们来总结一下React中数据传递的方式 单向数据流 当前组件的state以props的形式流动时,只能流向比自己层级更低的组件: 以上的单向数据流是React数据中的基础传递方式,在实际项目中,组件嵌套的层级都会很深,我们就需要用到更加方便的信息传递方式了 状态集中管理 最经典的就是Redux啦,作为集中式状态管理容器,他提供可预测的状态管理,设计模式遵循flux模式,他的数据流也是严格单向的。 另外一个就是React内置的contextAPI啦,contextAPI使用起来更方便,在中小型的项目中也就没必要使用Redux啦。 ContextAPI一般需要createContext, useContext, context.Provider三大件,createContext创建一个全局环境,用provider包裹需要用到的组件,useContext在组件中调用。 发布订阅模型 接下来介绍状态管理的大杀器Zustand,最近的项目中一直在使用这个工具,比context API 和 Redux方便了无数倍 首先为什么选择Zustand呢? 按照官方的话来说Zustand是一个轻量,无样板,基于hooks的状态管理库。他的核心优势是: 对于常见的三种state,我们是有三种心智模型的 核心区别Zustand管理的是本地真相,React Query管理的是远程真相 实践 1. 按业务域区分slice 2. 组合Store – useBoundStore 3. 持久化 persist + partialize 4. 订阅 4.1 基础版订阅 4.2 进阶版订阅 selector + shallow 4.3 终极版订阅 *** 亮点 更加推荐的架构是不让组件直接接触store,而是通过语义化store做一个中间层 踩过的坑: 1. 直接解构整个store 等价于订阅整个store,任意的状态变化都会导致这个组件重新渲染 2. 把服务端数据塞进 Zustand 带来的问题是需要自己处理缓存,失效,刷新等机制,并且状态很快就失真了,因此还是建议直接使用react query了…

  • 长列表优化

    在处理大量数据的长列表时,浏览器经常会因为内存占用过高产生卡顿现象,那么如何优化长列表呢?清楚我们的MVP选手 – 虚拟滚动 虚拟滚动 仅渲染当前窗口可见的的部分列表,而不是将整个列表都渲染出来,这种方法可以降低页面的渲染时间和内存占用,从而提高页面的性能。 那么具体如何实现呢? 首先是模拟滚动,虚拟滚动嘛,我们页面上实际并没有原生的滚动功能,需要我们去模拟,我们需要做的就是根据用户滚动的位置重新渲染可见的列表,当这个操作时间跨度足够小时,它看起来就像在滚动一样。 具体实现方法如下:

  • JS中的链式操作

    1. jQuery中的链式操作 想必老前端们对jQuery都不陌生,毕竟在Angular, React, Vue等优秀的框架初始出世之前是我们的必备工具。 jQuery的一大优点就是其经典的链式操作。而链式操作具体是怎么实现的呢?今天我们来一起回顾一下。 说到jQuery的链式操作原理,我们知道,JS中函数在没有返回值时会隐式返回一个undefined,而在jQuery中我们会让所有方法都返回一个this对象,这样链后边的方法就可以继续在this的环境中执行。这种链模式是原理是基于原型继承的,当然我们也可以使用ES6的class写法,我们来手动实现一下: 2. Proxy实现链式操作 利用Proxy我们也同样可以实现链式操作 链式操作的优缺点 先说缺点吧,因为链式操作要返回this对象,所以在需要返回值的情况下,如get操作,是不能继续接其他的链方法的,这个天然符合jQuery的特性,操作DOM,不需要返回值 再说优点,联想一下Promise,promise每次都会返回一个promise对象,通过then方法指定回调函数。 这种方法使得函数的操作更加直观,同时也不会像回调函数一样相互耦合。

  • JS中的Proxy

    Proxy直译是代理的意思,在JS中通常用作在目标对象之前架设一层代理,外界对该对象的访问,都必须先通过这层代理,因此可以对外界的访问进行修改和过滤 第一个参数target是所要代理的目标对象,第二个参数handler是一个配置对象,这个对象需要提供一个处理函数,用该函数对目标对象进行拦截。 Proxy的拦截操作列表 1. get操作 get操作用于拦截对象属性的读取,get方法接收三个参数,依次为目标对象,属性名,和proxy实例本身,第三个参数是可选的 2. set操作 set操作用来拦截对对象内属性的赋值,可以接收四个参数,依次为目标对象,属性名,属性值,proxy实例本身,最后一个参数可选。 3. 其他操作

Got any book recommendations?