Hi there 👋

Welcome to my blog

实现上传图片以及相关概念

效果 <input type="file"> 我们使用 <input type="file"> 来允许用户选择文件。 <!-- `accept="image/*"` 表示只允许上传图片格式的文件。 --> <Input id="addPic" type="file" accept="image/*" /> 监听 onchange 获取已选择图片的信息,files 包含了一列 File 对象的 FileList 对象。FileList 的行为像一个数组,所以你可以检查 length 属性来获得已选择文件的数量。 每个 File 包含下列信息: name:文件名。 lastModified:一个数字,指定文件最后一次修改的日期和时间,以 UNIX 新纪元(1970年1月1日午夜)以来的毫秒数表示。 lastModifiedDate :一个 Date 对象,表示文件最后一次修改的日期和时间。这被弃用,并且不应使用。使用 lastModified 作为替代。 size:以字节数为单位的文件大小。 type:文件的 MIME 类型。 webkitRelativePath:一个字符串,指定了相对于在目录选择器中选择的基本目录的文件路径(即,一个设置了 webkitdirectory 属性的 file 选择器)。 这是非标准的,应该谨慎使用。 document.getElement('addPic').onchange = function () { // console.log(this.files) } 预览 可以将 File 对象转换为 Blob 或 base 64 显示在页面上。...

July 7, 2021 · 2 min · vdorchan

V8 垃圾回收笔记

为何需要垃圾回收 JS的垃圾回收系统会自动进行,为了让系统可以重复利用内存,避免内存暴增 V8引擎的内存限制 为了减少性能引起的影响,基于以下两点的原因,限制了V8引擎的内存大小。 node 可以手动设置。 • 因为JS单线程,垃圾回收会阻碍主线程逻辑 • 垃圾回收本身耗时 V8的内存结构 对象开始都会分配在**新生代(new_space)**中,该区域由两个半空间(semispace)构成。 一个处于激活状态的From空间,一个处于未激活的To空间。 当进行垃圾回收时,From中的空闲对象被自动回收,存活对象则被复制到To空间。 复制完成后,From变成To,To变成From。 这个过程用了 Scavenge算法。 当: 对象经历过一次 Scavenge算法 To的内存空间超过了 25% 对象就会进入到老生代中,这个过程叫对象晋升。 在老生代中,采用新的算法Mark-Sweep(标记清除)和Mark-Compact(标记整理)来进行管理。 引用计数 有个已经被淘汰的算法叫引用计数,当没有对象饮用的时候,该对象就会被回收。 但当出现循环引用的时候,垃圾回收器无法正确清除对象引用,容易发生内存泄漏。 Mark-Sweep Mark-Sweep会从根结点出发,遍历访问所有可以访问到的子节点,并将其标记为活动的,非活动的则直接清除。 根结点包括 • 全局对象 • 本地函数的局部变量和参数 • 当前嵌套调用链上的其他函数的变量和参数 Mark-Compact 经历过Mark-Sweep之后,因为清理的内存地址不是连续的,所以会出现内存碎片。 Mark-Compact 算法就是为了解决这种内存碎片。 它会将标记的活动对象都推到内存的一端,然后回收另一端的非活动对象。 弱引用 WeakSet 和 WeakMap 中的键名所引用的对象都是弱引用,在垃圾回收的工程中,不会将键名对该对象的引用考虑进去。 适合存储Dom节点。 参考:https://juejin.cn/post/6844904016325902344

July 5, 2021 · 1 min · vdorchan

缓存总结

浏览器在加载资源时,根据请求头的expires和cache-control判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。 如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过last-modified和etag验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源 如果前面两者都没有命中,直接从服务器加载资源 相同点 如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据; #### 不同点 强缓存不发请求到服务器 协商缓存会发请求到服务器。 强制缓存 Cache-Control: no-store:没有缓存。缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。 Cache-Control: no-cache:缓存但每次都验证。带着相关验证字段将请求发送到服务器。服务器会验证所描述的缓存是否过期。若未过期(304 NOT MODIFIED),则使用本地缓存。 私有和共有 Cache-Control: public:可以被所有用户缓存(多用户共享),包括终端和CDN等中间代理服务器 Cache-Control: private:只能被终端浏览器缓存(而且是私有缓存),不允许中继缓存服务器进行缓存。 过期 Cache-Control: max-age=<seconds>:表示资源能够被缓存(保持新鲜)的最大时间。 验证方式 Cache-Control: must-revalidate:意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。 Pragma 头 Pragma 是HTTP/1.0标准中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头没有明确定义这个属性,所以它不能拿来完全替代HTTP/1.1中定义的Cache-control头。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。 协商缓存 用户点击刷新按钮时会开始缓存验证。如果缓存的响应头信息里含有"Cache-control: must-revalidate”的定义,在浏览的过程中也会触发缓存验证。另外,在浏览器偏好设置里设置Advanced->Cache为强制验证缓存也能达到相同的效果。 当缓存的文档过期后,需要进行缓存验证或者重新获取资源。只有在服务器返回强校验器或者弱校验器时才会进行验证。 强校验器 ETag If-None-Match 响应头:Etag 请求头:If-None-Match If-None-Match: <etag_value> If-None-Match: <etag_value>, <etag_value>, … If-None-Match: * If-None-Match 是一个条件式请求首部。对于 GETGET 和 HEAD 请求方法来说,当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为 200 。对于其他方法来说,当且仅当最终确认没有已存在的资源的 ETag 属性值与这个首部中所列出的相匹配的时候,才会对请求进行相应的处理。...

May 20, 2021 · 1 min · vdorchan

React项目优化的最佳实践

构建优化及开发体验 旧项目使用了 antd-design-pro,基于 umi 框架,umi 是一个整合了多个技术栈的框架,如状态管理、路由、webpack打包等。对于开发者来说,这些功能的初始化和具体配置被封装起来,开箱即用确实方便。但这么一个黑箱,除了通过官方提供的配置,我几乎无法有更进一步调整。 于是我移除了 umi,转而使用 webpack 5 从零搭起一个开发环境,过程花了不少时间去反复读文档,了解最佳实践,踩了不少坑。然而结果还是不错的,最新的技术可以带来不错的效益,实践过后也沉淀了一些东西。 依赖安装 - pnpm 与 yarn pnp npm3 维护了一个扁平的依赖结构,虽然解决 npm2 的嵌套关系过深的问题,这也使得 Node_modules文件夹变得混乱。想必身为前端基本都苦 npm 久矣,每次安装,除了网络问题,数量繁多的小文件读写,也使得这个过程艰难险阻。 后来 Facebook 带来了 Yarn,它提供了一些更好的体验,比如 lock 文件、更好的缓存控制等。但其并没有改变巨大的NODE_MODULES目录。你的电脑依然要消耗空间去存储很多重复的模块。 在之后,yarn 推出了一个被称为即插即用(pnp)的功能,它直接移除了NODE_MODULES,而是使用 一个 pnp.js 的文件,将文件指向缓存中的映射。因为少了NODE_MODULES,在 webpack 5 之前,你就需要去配置 webpack 的 resovle 模块的模块解析规则,或者使用PnpWebpackPlugin插件。而 webpack 5 则是原生支持,不需要额外的配置。 pnpm 同样是用来作为 npm 的替代,它不会去计算包的嵌套关系,并且通过硬连接将 NODE_MODULES内的文件指向机器内的一个全局存储目录,这样同一个模块只需要安装一次。安装方式很简单,比如通过脚本安装: macOS, Linux 等系统 curl -f https://get.pnpm.io/v6.js | node - add --global pnpm Windows (使用 PowerShell): (Invoke-WebRequest 'https://get.pnpm.io/v6.js' -UseBasicParsing).Content | node - add --global pnpm 安装后,就像npm install一样,使用pnpm install即可。...

May 16, 2021 · 4 min · vdorchan

javascript-设计模式与开发实践三

设计原则和编程技巧 可以说每种设计模式都是为了让代码迎合其中一个或多个原则而出现的,它们本身已经融入了设计模式之中,给面向对象编程指明了方向。 前辈总结的设计原则通常值的是单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则和最少知识原则。 单一职责原则(SRP) SRP原则体现在:一个对象(方法)只做一件事情。如果一个方法承担了太多的职责,并且这些职责耦合在一起,一个职责发生变化影响到另外的职责的实现。这种耦合性得到的是低内聚和脆弱的设计。如果两个职责总是同时变化的,那么也不必一定要分离他们。有时即使耦合在一起,但没有发生改变的征兆,那么也许也可以不必主动分离他们,而是等到需要重构的时候。有时候为了方便性,我们可以选择违反规则,去牺牲稳定性。比如 jQuery 的 attr 方法,内部实现很复杂庞大,维护会有一些困难,但对于使用者很方便。优缺点 优点是,降低了单个类或者对象的复杂度,有助于代码复用和进行单元测试。当一个职责需要改变的时候,不会影响到另外一个职责。缺点是,增加代码复杂度,增加了对象之间相互联系的复杂度。 最少知识原则(LKP) LKP 说的是一个软件实体应当尽可能少地与其它实体发生相互作用。设计模式中的体现: 中介者模式(增加一个中介者对象,让所有相关的对象都通过中介者对象来通信) 外观模式(隔离客户与复杂子系统的之间的联系,客户不用去了解子系统的细节) 原则只是一种指导,要根据具体的环境来决定是否遵守。 开放-封闭原则(OCP) 软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。 开放和封闭:比起修改源代码,增加代码是成本更低,且更不容易出 bug 的方式。 利用对象多态性消除条件分支。 找出变化的地方,封装变化,可以把系统中稳定不变的部分和容易变化的部分隔离开来。 最初编写代码的时候,因为需求排期不是无限的,可以先假设变化永远不会发生,这样有利于迅速完成需求。当变化发生且对我们接下来的工作造成影响了,可以回过头来封装这些变化的地方,然后确保我们不会掉进同一个坑里。 接口和面向接口编程 通常讲到的接口 API 接口,主动暴露接口来通信。 一些语言提供的关键字,比如 Java 的 interface。 更加抽象,接口时对象能响应的请求的集合。 传统的面向对象语言比如 Java,会有抽象类和 interface 来限制,而 JavaScript 是一个动态类型语言,类型本身在 JavaScript 是一个相对模糊的概念。可以认为,JavaScript 中的非基础类型都可以看成“天生”被“向上转型”成了 Object。因为不需要进行向上转型,接口在 JavaScript 中的最大作用就退化到了检查代码的规范性。在 JavaScript 中,我们一般会手动编写一些接口检查的代码。 代码重构 1、提炼函数 需要重构的函数:如果一个函数过长,并且需要很多注释才能让这个函数显得易读一些。将可以独立出来的代码拿出来放进另一个独立的函数,有以下好处: 避免出现超大函数。 独立出来的函数有助于函数复用。 独立出来的函数更容易被覆写。 独立出来的函数如果有一个良好的命名,它本身就起到到了注释的作用。 2、合并重复的条件片段 3、把条件语句提炼成函数 比如: age > 50 && gender = 'woman' 改成 isOldWoman() 4、合理使用循环 如果有些代码负责的是一些重复性的工作,那么可以使用循环完成同样的功能。 5、提前让函数退出代替嵌套条件语句 6、传递对象参数避免过长的参数列表 7、尽量减少参数数量 8、少用三目运算符 条件分支逻辑简单时,可以使用三目运算符,但是如果条件分支逻辑非常复杂,则用if、else会更合适,因为阅读更加容易,且方便修改。 9、合理使用链式调用 链式调用的时候,虽然可以节省一些中间变量。但带来的坏处时在调试的时候非常不方便,如果一条链中有错误出现,我们必须得先将这条链拆开才能加上一些 log 或者增加断点。除非链条相对稳定,且不容易发生修改,否则还是选择使用普通调用的形式。 10、分解大型类 面向对象设计鼓励将行为分布在合理数量的更小对象之中。把行为委托给这些其它类的对象来执行。 11、用 return 推出循环

March 13, 2021 · 1 min · vdorchan

javascript-设计模式与开发实践二

设计模式 单例模式 单例模式的定义是:保证一个类只有一个实例,并提供一个访问它的全局访问点。传统面向对象语言中,单例对象一般从“类”中创建而来。但 JavaScript 是一门无类(class-free)语言,创建对象的方法很简单,先创建一个“类”,其实很没必要。按照上面其定义,虽然全局变量不是单例模式,但在 JavaScript 中我们经常会把全局变量当成单例来使用,但要留意命名空间污染,它很容易被覆盖。 var a = {}; 惰性单例 惰性单例指的是在需要的时候才创建对象实例,是单例模式的重点。 var createDiv = (function () { var div return function () { if (!div) { div = document.createElement('div') div.style.display = 'none' document.body.appendChild(div) } return div } })() // 根据单一职责原则,可以写个通用的 var getSignle = (function (fn) { var result return function () { return fn || (result = fn.apply(this, arguments)) } })() 策略模式 策略模式的定义是:定义一系列的算法,把他们一个个封装起来,并且是他们可以相互替换。一个基于策略模式的程序至少由两个部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。例子:缓动动画 Tween、表单验证P86。计算年终奖的代码:...

March 13, 2021 · 3 min · vdorchan

javascript-设计模式与开发实践一

基础知识 前言 设计模式是在某种场合下对某个问题的一种解决方案。 在我们试图解决一些问题的时候,说不定别人也遇到过一样的问题,并且把他们整理成了模式,提供了一种通用的解决方案。 设计模式实际上是解决某一种问题的一种思想,与具体的语言无关。 除了主流的面向对象语言,在函数式的语言中,设计模式依然存在。 一些设计模式的实现会因为语言的不同而不同。 软件的成本并非全部在开发阶段,虽然设计模式可能会增加复杂度,或带来一些额外的代码,但它会让人们写出可复用和可维护性高的程序。 所有设计模式的实现遵循一条原则:“找出程序中变化的地方,并将变化封装起来”。 很多模式的类图和结构很相似但不重要,辨别模式的关键是这个模式出现的场景,以及帮助我们解决了什么问题。 一、面向对象的 JavaScript JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承。 ES6 的 class 是语法糖。 编程语言类型和鸭子类型 编程语言按照数据类型大体可以分为两类,一类是**_静态类型语言_**,另一类是**_动态类型语言_**。**_静态类型语言_**在编译时便以确定变量的类型,而**_动态类型语言_**要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型。** **静态类型语言**的优点是可以提早发现错误,编译器可以针对这些数据类型的信息做一些优化。缺点是强契约不够灵活。 _动态类型语言_的优点是简洁代码量少,缺点是有些类型相关的错误可能到运行的时候才能知道。 JS 是_**动态类型语言。**_ _鸭子类型_强调关注对象的行为,而不是对象本身。动态类型语言 不必借助超类型的帮助,假如一个对象正确实现了 push 和 pop 方法,那它就可以被当作栈来使用。 多态 多态的思想是把“做什么”和“谁去做”分离开来。下面代码,我们不关注传进来的是那种对象,只要它有 makeSound 方法。 // 不变的部分 function makeSound (animal) { animal.sound() } // 可变的部分 const Duck = function () {} Duck.prototype.sound = function () { console.log('嘎嘎嘎') } const Chicken = function () {} Chicken....

March 12, 2021 · 2 min · vdorchan

前端模块化

模块化的理解 模块化这件事,无论在哪个编程领域都是相当常见的事情,模块化存在的意义就是为了增加可复用性,以尽可能少的代码是实现个性化的需求。 模块化的计划进程 全局 function 模式:将不同的功能封装成不同的全局函数 function myModule1 () {} function myModule2 () {} namespace模式:简单对象封装 let myModule = { msg: 'hello world', say() { console.log(this.msg) } } IIFE模式:匿名函数自调用 // myModule.js ;(function (window) { let msg = 'hello world' function say () { console.log(msg) } window.myModule = { say } })(window) // 另一个js myModule.say() IIFE模式增强:引入依赖(现代模块实现的基石) ;(function (window, $) { let msg = 'hello world' function say () { $('body')....

March 22, 2020 · 3 min · vdorchan

理解 CSS 布局和 BFC

正常布局流 (normal flow) 正常布局流是指在不对页面进行任何布局控制时,浏览器默认的HTML布局方式。 在 normal flow 中,元素按照其在 HTML 源码中出现的先后位置至上而下布局。在这个过程中,行内元素水平排列,直到当行被占满然后换行。块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是 normal flow 定位,也可以说,普通流中元素的位置由该元素在 HTML 源码中的位置决定。 以下这些布局技术可能会覆盖默认的流式布局 display 属性: 像 block、inline 或者 inline-block 这样的标准值可以改变元素在 normal flow 中的行为。而使用像 CSS Grid 和 Flexbox 的值允许我们使用完全不同的方式来布局。 浮动(Floats): 应用 float 值,诸如 left 能够让块级元素互相并排成一行。 position 属性: 正常布局流中,默认为 static ,可以使用其它值会来为元素使用不同的布局方案。 表格布局:用于布置表格 多列布局(Multi-column layout):可以使块的内容按列布局 脱离文档流 An element is called out of flow if it is floated, absolutely positioned, or is the root element. An element is called in-flow if it is not out-of-flow....

April 24, 2019 · 2 min · vdorchan

前端性能优化与浏览器渲染

对性能优化的知识点做了些总结,如有纰漏,跪求批评指正。 在我们共同推动网页实现更多功能的过程中,将遇到一个常见的问题:性能。 如今,网站拥有比以往更多的功能,以至于许多网站都将精力用于在各种网络条件和设备上提供更高的性能。 不过,性能问题多种多样。轻微性能问题可能只会导致微弱的延迟,给您的用户带来短暂的不便。而严重的性能问题可能导致您的网站完全无法访问,无法对用户输入进行响应或两者同时发生。 内容压缩和优化 总体来说,我们要避免不必要的下载,首先要去评估每个资产的表现:其价值及其技术性能。然后根据这些资源是否提供了足够的价值来决定是否要移除它们。 比如一些 CSS 框架的开销可能导致渲染延迟严重,你可以视情况移除不必要的开销,以加速渲染。或者,移除不是必须的框架(使用更小的框架代替,例如使用 zepto 代替 jQuery,使用 Preact 代替 React) 而那些必要的资源,我们应该要对它进行压缩优化,根据资源(文本、图像、字体、源码等)的不同,我们使用不同技术压缩。 除了压缩,还可以对不同资源进行特定的优化: 图像优化 选择合适的尺寸 使用 CSS3 效果和网页字体代替图像 由于人眼的工作方式的缘故,可以适当进行有损压缩 假如浏览器支持,可以使用 WebP 和 JPEG XR 等压缩率更高的新格式 使用 <picture> 和 <img srcset> 实现响应式图片使用 <picture> 和 <img srcset> 来完成。给 img 或设置了 background 的 CSS 属性的元素,将其设置为 display: none,并不能其阻止加载图片。 使用视频代替 GIF, 当使用视频代替动画 GIF 时,可以减小数据量,并可能减少系统资源的使用。 脚本优化 减少重排(reflow)和重绘(repaint)操作 缓存 DOM 元素、DOM 列表长度 length、属性值 使用事件委托,避免批量绑定事件 尽量使用 ID 选择器,因为它一经找到就停止查找,而使用类选择器的话将遍历整个dom 移动端使用 touch 事件代替 click 事件,因为 click 有 300ms 延迟 使用节流(throttle)和防抖(debounce)函数减少性能消耗 HTML优化...

April 23, 2019 · 4 min · vdorchan