- 博客(172)
- 收藏
- 关注
原创 react diff
遍历剩余的newChildren,(lastPlacedIndex 是最后一个可复用的节点在 oldFiber 中的位置索引)逐个在 map 中寻找 oldFiber 中可复用的节点,如果找到可复用的节点,则将 oldIndex 与 lastPlacedIndex 比较,如果 oldIndex 与 lastPlacedIndex 小,则该节点需要右移,将新的 Fiber 节点标记为 Placement。若key相同,但元素类型不同,oldfiber标记为delete,继续遍历。第一轮遍历更新的节点。
2024-03-04 22:28:57
471
原创 JS垃圾回收机制
也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域,为解决这个问题,js引擎采用了对象晋升策略,也就是经过两次垃圾回收依然还存活的对象,会被移动到老生区中。使用增量标记算法,可以把一个完整的垃圾回收任务拆分为很多很小的任务,这些小的任务执行时间较短,可以穿插在其他js任务中执行,类似于react的fiber架构思想。v8新生代的垃圾回收中,因其空间较小,且存活对象较少,所以全停顿的影响不大,但老生代不同,如果占用主线程时间过久,主线程是不能做其他事情的。第一步是标记空间中活动对象和非活动对象。
2024-01-24 14:44:53
1265
原创 单点登录(SSO)
利用cookie的这个特性,我们只需要将cookie的domain设置为父域的域名,同时将cookie的path设置为根路径,将session ID/Token保存在父域中。用户与系统创建的对话是局部对话,用户与sso创建的对话是全局对话。用户访问系统1的受保护资源,系统一发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数。sso认证中心检验用户信息,创建用户与sso之间的会话,称为全局会话,同时创建授权令牌。系统1使用该令牌创建与用户的对话,称为局部对话,返回受保护资源。
2024-01-18 14:41:28
464
原创 chrome浏览器并发限制及其突破手段
对于chrome来说,同域名下资源加载的最大并发连接数为6(源码中写死),当资源文件大于6时,多于6个的文件就会进入待定,等第一批加载完才会加载第二批的6个图片资源,这样就增加了等待时间。http/1有并发限制,http/2没有。那么为什么chrome会做出如此的限制呢?
2024-01-16 18:42:41
2956
原创 隐式转换规则
引用类型与值类型进行比较,引用类型先转换为值类型(调用[ToPrimitive])String 与 Number进行比较,String 转化为Number。Boolean 与其它类型进行比较,Boolean转换为Number。null,undefined与其它任何类型进行比较结果都为false。null 与 undefinde进行比较结果为true。引用类型与引用类型,直接判断是否指向同一对象。NaN不等于任何其它类型。
2022-09-08 23:12:15
147
原创 手写Promise.all
4.但凡有一个Promise被Reject掉,Promise.all失败。2.传入一个数组,其中包含Promise,也可包含普通数据。1.传入一个Iterable,但大多数情况下是数组。6.所有数据resolve之后,返回结果。5.保持输出数组位置与输入数组一致。3.数组中Promise并行执行。
2022-09-05 12:39:31
230
原创 [‘1‘,‘2‘,‘3‘].map(parseInt)解析
parseInt(“3”,2) radix为2,用二进制来解析,但value应该为"1" / “2”,因此返回NaN.。radix:取值范围2-36之间的整形。当参数为 0,parseInt() 会根据十进制来解析。parseInt(“1”,0) radix为0,parseInt()根据十进制来解析,结果为1。parseInt(“2”,1) radix为1,不在radix取值范围内,NaN。string:需要转化的字符。
2022-09-04 22:20:13
208
原创 ES6转为ES5 AST
Babel如何将ES6转化为ES5的呢?转换过程:分为三步:1.babylon进行解析第一步主要是将ES6语法解析为AST抽象语法树。2.Transform转换第二步是将打散的AST语法进行处理,在这个阶段可以将ES6代码进行相应的转换。3.Generator生成第三步根据处理后的AST再生成可执行的代码。wAST是什么?AST是源代码的抽象语法的树状表示,树上的每个节点都表示源代码中的一种结构,所以是抽象的,抽象表示把JS代码进行了结构化的转化,转化为一种数据结构。是一个大的JSON对
2022-09-04 14:48:08
688
原创 Promise妙用
红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次;如何让三个灯不断交替重复亮灯?(用Promise实现)使用Promise实现每隔1S输出1,2,3。
2022-08-30 12:58:32
138
原创 sort内部实现原理
可以看到,字符串排序是没问题的。但数字排序不正确,因为数字转换为字符串后字符串的第一个元素的unicode决定了元素的排序。实际上,当数据量很大时,快速排序优势更大。但当数据量较小时,插入排序性能会超过快速排序。compareFunction用来指定某种顺序进行排列的函数,如果不写。a取值范围nums[1]–nums[nums.length-1]b取值范围nums[0]–nums[nums.length-2]理论上,快速排序的时间复杂度是O(nlogn),插入排序是O(n2)...
2022-07-20 09:50:23
289
原创 JS异步发展史和async await原理初探
asyncawait的实现是依靠generator函数和promise实现的。gen函数执行返回值不是Promise,asyncFn执行返回值是Promise。但返回的是promise对象使用promise.then方法得到具体的值。gen函数执行的操作是不完善的,因为并不确定有几个yield,不确定会嵌套几次。gen函数需要执行相应的操作,才能等同于asyncFn的排队效果。在generator函数的yield后面接promise。...............
2022-07-17 21:02:27
159
原创 大文件上传
接收到每一个切割文件后,1.先进行multiparty解析,2.将切片存储到hash值命名的文件中3.检查文件中是否存在当前切片(存在的话不再进行任何的处理达到文件秒传的效果;1.找到hash对应的文件夹2.将所有的切片文件排序,合并,生成最终的大文件。3.删除切片文件夹4.告知前端上传成功,并且发送文件url给前端。5.待监听到所有请求都成功发出去后,给服务端发出合并请求(服务端合并文件成新文件,将保存hash切片的文件删除)上传成功的切片客户端移除掉,上传失败的切片重新发送请求。...
2022-07-15 11:29:23
171
原创 1px问题
物理像素:显示器上的真实像素,每个像素的大小是屏幕固有的属性。设备分辨率描述的就是这个显示器的宽和高是多少个设备像素。例如:1920*1080。设备独立像素:操作系统定义的像素单位。操作系统将设备独立像素转化为设备像素,从而控制屏幕上真正的物理像素点。CSS属于设备独立像素。设备像素比 = 物理像素 / 设备独立像素dpr = 1 一个物理像素显示一个设备独立像素dpr = 2 四个物理像素显示一个设备独立像素出现移动端1px问题主要是因为设备像素比不为1导致的。在pc上dpr =
2022-05-25 23:04:16
174
1
原创 前端性能优化方案
1.减少http请求次数2.使用http2.0代替http1.1 (头部压缩,服务器推送,多路复用,二进制传输)3.静态资源使用CDN (CSS,HTML,img)4.css放头部 JS文件放底部 (CSS不阻止页面的解析,但组织页面的渲染) (JS阻止页面的解析)5.使用iconfont代替图片6.使用图片懒加载7.按需加载按需加载就是把不同路由对应的组件分割成不同代码块。如果没有使用懒加载,项目打包后所有JS都在一个文件中,容易造成页面长时间白屏。使用按需加载,需要的时候加载页面
2022-05-25 21:22:27
187
原创 JS内存泄漏
内存泄漏:被分配的内存,既无法使用,又无法被回收。直到浏览器进程结束。造成的原因:1.被遗忘的定时器定时器用完之后 手动关闭 clearInterval() clearTimeout()2.console.log()console.log()中接受的对象不会被垃圾回收3.DOM泄漏 let root = document.querySelector('#root') let ul = document.querySelector('#ul') let li3 = document.
2022-05-23 23:36:34
464
原创 weakSet weakMap
weakSet1.成员只能是对象2.weakSet中对象都是弱引用weakMap1.键只能是对象2.键名所指向的对象为弱引用。引用的概念:强引用:如果持有对一个对象的引用,那么这个对象就不会被垃圾回收。弱引用:一个对象若只被弱引用所引用,则被认为是不可访问。并且可能在任何时刻被回收。正因如此weakSet weakMap都不能被遍历。...
2022-05-23 23:18:35
178
原创 取消axios请求
通过 cancelToken 实现具体代码如下: <script> //获取按钮 const btns = document.querySelectorAll('button'); //2.声明全局变量 let cancel = null; //发送请求 btns[0].onclick = function () { // 检测上一次的请求是否已经完成
2022-05-21 21:27:38
102
原创 Object 和 map 数据类型区别
注:序列化的作用:在传递和保存对象时。保证对象的完整性和可传递性。将对象转换为有序字节流,以便在网络上传输或保存在本地。iterator:是一个接口,拥有这个接口的数据结构可以直接用for…of进行遍历。Array Set Map String argumentsMap的方法map.set(key,val)map.get(key)map.delete(key)map.has(key)map.clear()map.keys() 返回键的集合map.values() 返回值的集合m.
2022-05-20 00:13:51
155
原创 项目难点总结(羽乐购)
一,list界面左右better-scroll的关联点击左侧右侧滚动1定义变量height=0;用来记录每个li距离顶部的高度,初始化为零,因为点击左侧第一个li时(推荐)不会上移。2.定义一个数组allHeight用来盛放每个li距离顶部的高度。用左侧的index值与allHeight中的值进行对应。通过better-scroll的scrollTo方法进行右侧的滚动let height = 0; this.allHeight.push(height); let do
2022-05-19 10:30:23
102
原创 数组转树/树转数组
数组转树pid指向的id值就是父元素。 <script> const arr = [ { id: 1, pid: null, name: '研发部' }, { id: 2, pid: null, name: '管理部' }, { id: 3, pid: 1, name: "前端研发部" }, { id: 4, pid: 1, name: "后端研发部" },
2022-04-26 00:14:21
1433
原创 数组与类数组
什么是类数组?类数组的原型是一个对象。具有length属性,属性值为索引属性,无数组的方法。常见的类数组argumentsgetElementsByNamegetElementsByTagNamegetElementsByClassNamequerySelectorAll类数组转数组第一种Array.prototype.slice.call(arguments)第二种扩展运算符[...arguments]第三种循环遍历添加第四种arguments.__proto__
2022-04-24 22:52:37
133
原创 JS获取DOM 操作DOM的方法
document.getElementById(’‘)上下文是documentdocument.getElementsByName('')上下文是document返回类数组document.getElementsByTagName('')上下文可以是document,也可以是一个元素。返回类数组document.getElementsByClassName('')上下文可以是document,也可以是一个元素。返回类数组document.querySelector(' ')
2022-04-24 21:49:26
220
原创 CSS加载条
<style> body { background-color: gray; } .loading-box { margin: 100px auto; height: 150px; width: 250px; } .loading { height: 20px; ...
2022-04-24 20:56:59
394
原创 后端给你1W条数据,怎么保证前端在渲染的时候页面不会卡
document.createDocumentFragment()用来创建一个虚拟的节点对象,节点对象不属于文档树。当需要添加多个DOM元素时,可以先把DOM添加到这个虚拟节点中。然后再统一将虚拟节点添加到页面,这会减少页面渲染DOM的次数。window.requestAnimationFrame接受参数为函数,比起setTimeout和setInterval有以下优点:1.把每一帧中的所有DOM操作集中起来,在一次的重排/重绘中完成。每秒60帧。2.在隐藏或者不可见的元素中,requestAn
2022-04-24 18:36:09
5153
2
原创 为什么JS是单线程的?为什么操作DOM非常消耗性能?
进程:进程是操作系统进行资源分配的基本单位。线程:线程是CPU调度和分派的基本单位。JS为什么是单线程的?这主要与JS的用途有关,JS作为浏览器的脚本语言。主要是实现用户与浏览器的交互。假如是多线程的,会出现一种情况:一个线程是要修改某一个DOM元素。而另一个线程是要删除这个DOM元素,那么就会产生冲突。所以使用单线程。为什么操作DOM非常消耗性能?两点原因:1.浏览器的JS引擎与DOM引擎共享一个主线程。当调用DOM时,会将JS引擎挂起然后再启动DOM引擎。调用结束后,重启JS引擎继续执行。这
2022-04-24 14:42:19
489
原创 为什么css在页面head,js在body尾部
这与html页面渲染有关。1.解析html生成DOM树2.解析css生成CSSOM3.合并DOM和CSSOM生成渲染树4.计算节点在页面中的位置和大小,生成布局树5.对布局树进行分层,生成分层树6.而后将分层树进行渲染,生成页面。CSS在加载过程中,不影响HTML的解析。但影响HTML渲染。假如将css放在body的尾部,会产生一种情况。解析html生成DOM树,而后没有css。所以直接生成渲染树,然后生成布局树渲染网页。直到解析到css时,生成CSSOM。CSSOM与DOM树合并生成渲染树
2022-04-18 21:51:51
551
原创 判断两个对象是否相等
function isObjectValueEqual(a, b) { let a1 = Object.getOwnPropertyNames(a) let b1 = Object.getOwnPropertyNames(b) if (a.length != b.length) { return false } for (let i = 0;...
2022-04-18 13:47:35
429
原创 slice substr substring
slice 数组和字符串都可以使用substr和substring都是字符串的方法,数组不可以使用。返回截取的字符串。substring和slice使用方法相似,可设置两个参数。(start,end)可以取到start不可以取到endsubstr第一个参数是开始截取的位置。第二个参数是截取的字符个数。当slice substring substr都只有一个参数时。默认从第一个参数开始截取到最后。当第一个参数大于第二个参数时,slice无效返回空。substring自动将两个参数调转。subst
2022-04-16 12:19:40
1413
原创 手写JSONP
const jsonp = ({ url, params, callBackName }) => { const getUrl = () => { let urlStr = '' //循环params参数对象 拼接参数 for (let key in params) { if (params.hasOwnProperty...
2022-04-09 00:58:32
158
原创 手写AJAX
xhr的请求状态readystate的五个参数0 请求未初始化 send()未调用1 与服务器建立连接 send()未调用2 请求已发送,正在处理中3 请求未完成 返回部分数据4 请求完成 返回全部数据 <script> // GET方法 function myAJAX(url) { return new Promise((resolve, reject) => { l
2022-04-09 00:47:08
145
原创 函数柯里化
柯里化的概念:是把接收多个参数的函数变换成接收一个单一参数的函数,并且返回接收余下参数的新函数的技术。函数柯里化的优点:1.参数复用(利用闭包)2.延迟执行(bind方法实现机制就是函数柯里化)关于函数柯里化的性能:函数嵌套创建多个闭包会带来大量花销。但是相对于操作DOM来说,柯里化带来的花销不值一提。所以可以放心使用。手写实现: <script> function curry(fn, ...args) { // 1.先判断参数的个数
2022-04-08 21:13:26
104
原创 解析url参数为对象
<script> let url = 'http://www.abc.com/?use=rose&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; function parseURL(url) { // 用?做分割分为数组 let [, arr] = url.split("?") //用&做分割分为数组 .
2022-04-08 17:00:58
435
原创 JS拖拽元素
拖拽时 开始:dragstart 进行中:drag 结束:dragend进入区域:进入时:dragenter 进入后:dragover 离开:dragleave 放置:drop思路:开始拖拽时:给事件设置e.dataTransfer.set('XXXX',e.target.id)取消进入后和放置的默认事件 e.preventDefault()放置时获取元素id let data = e.dataTransfer.get('XXXX')通过元素ID获取DO
2022-04-08 01:03:13
235
原创 手写订阅发布
<script> class Observer { constructor() { // 消息池 this.message = {} } $on(name, fn) { // 如果没有绑定过事件,则添加消息队列[],然后加入回调 if (!this.message[name]) ..
2022-04-07 22:52:44
186
原创 手写new
手写new <script> // new操作符运行步骤 // 1.创建一个空对象 // 2.空对象的__proto__指向构造函数的prototype // 3.让构造函数的this指向空对象 // 4.返回新对象 执行构造函数中的代码 // 注意:1.若是一个普通函数使用new返回 {} 一个空对象 因为没有使用this // 2.若构造函数中有返回值,并且返回值是
2022-04-07 22:51:29
146
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人