Spiga

前端提升5:手撸vue2响应式+渲染

2025-03-29 16:26:46

摘要:阅读vue(2.6)的源码,data响应式大概有如下4个过程: 数据代理:core/instance/state.js---vue函数---initMixin---initState---数据遍历---observer/index.js---Observer--- defineReactive---defineProperty 数据装载:$mount---装载template---compileToFunctions---mountComponet---创建【渲染Watcher】---Watcher.get()---Watcher.get()依赖收集---Dep.target就是当前的Watcher(data中的属性—dep-----watcher 形成双向引用) 数据相应式:需要修改data属性---触发setter回调执行---通知dep上的watcher更新dep.notify()---遍历所有的watcher并调用watcher的update方法---调用run方法---调用get()方法实现页面渲染 数据渲染:vm.__patch__---createPatchFunction---patchVnode---双方都有孩子节点updateChildrendiff代理 以下我们参考vue的源码,记录实现data响应式的全过程 一、数据劫持 收先我们混入一个方法,给Vue对象添加一个内部_init方法,我们在这个内部方法中去实现需要的功能 //index.js import { initMixin } from ./init; function Vue(options){ // vue2 配置项 console.log(my vue 6666) this._init(options); // vue 内部约定 私有的方法或属性 一般是以 $ _ 开头 } initMixin(Vue); // 一执行,Vue就有_init方法 export default Vue //init.js 初始化 import { initState } from ./state; // 混入 类似于 对象语言的继承 // 在不改变这个函数的前提下,给这个函数增加方法 增强功能 // 原理是在prototype上添加方…… 阅读全文

前端提升4:Vue全家桶

2025-03-22 14:44:23

摘要:一、Vue3项目搭建 Node.js:是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O 模型,让JavaScript 运行在服务端的开发平台; 版本要求=12.0.0; npm:Nodejs下的包管理器;版本要求 6.x yarn:包管理器; yarn 包管理器是 npm 的一个替代方案,由Facebook于2016年10月发布。 Vite:是一个 web 开发构建工具,使用 Vite 可以快速构建 VUE 项目比webpack打包更加快速 快速的冷启动 即时的模块热更新 真正的按需编译 创建vite3项目:npm init vite,输入项目名称 安装依赖 cd vite-project 进入项目 依赖安装 npm install 或 cnmp i 运行vite项目:npm run dev 访问:http://localhost:5173 包管理工具Yarn的使用 yarn create vite:输入项目名称 cd vite-d2 安装依赖:yarn 项目启动:yarn dev 二、Vue3.2新特性 1. createApp 在 Vue 3 中,改变全局 Vue 行为的 API 现在被移动到了由新的 createApp 方法所创建的应用实例上。 import { createApp } from 'vue' const app = createApp({}) 该实例提供了一个应用上下文,由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法 import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' const app = createApp(App); app.use(store) app.use(router) app.mount('#app'); //合并之后的代码: createApp(App).use(store).use(router).mount('#app') 2. setup函数 setup函数是vue3中专门为组件提供的新属性。 创建组件实例,然后初…… 阅读全文

前端提升3:TS

2025-03-15 10:19:14

摘要:TypeScript 是一种由微软开发的自由开源的编程语言,他是JavaScript的一个超集,扩展了JavaScript的 语法,主要提供了类型系统和对 ES6 的支持。 一、类型定义 window.onload=function(){ //类型系统 let flag:boolean = false; //布尔类型 let num:number = 15; //数值类型 let str:string = 'abc'; //字符串类型 let str2:string=`hello,${str}`; let msg:string = `hello,${str},${num}`; let u: undefined = undefined; let n: null = null; //为什么要TS // function sum(n1:number,n2:number){ // return n1+n2 // }; // sum(10,20); // sum('10',20); let count:number = 10; count = 100; //声明的变量有多种类型——联合类型 let id:number | string = 10; id = '111'; //任意类型 :any 万能类型 let x:any = true; x = 111; x = 'abc'; //引用类型 //数组 let arr:number[] = [1,2,3,4,5]; //最简单的方法是使用「类型 + 方括号」来表示数组: number[] let arr2:string[] = ['a','b','hello']; let arr3:(number|string)[] = ['a',100,'hello']; let arr4:any[] = ['a',100,'hello']; //数组泛型 Array类型 let arr5:Arraynumber= [1,2,3,4,5]; let …… 阅读全文

前端提升2:ES

2025-03-08 15:14:23

摘要:一、let与const let用来声明变量,它的用法类似于 var 不存在变量提升 同一个作用域内不能重复定义同一个名称 有着严格的作用域 const 声明一个只读的常量。一旦声明,常量的值就不能改变。 保持let的不存在变量提升,同一个作用域内不能重复定义同一个名称,有着严格的作用域 const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动 window.onload = function () { // let 和var的不同 // 1、不存在变量提升 // console.log(a); // var a = 100; // //解析过程 // //预解析 // var a; // //逐行解析 // console.log(a); // a = 100; // // // console.log(a); //Cannot access 'a' before initialization // let a = 100; //2、同一个作用域内不能重复定义同一个名称 // var a = 10; // var a = 100; // console.log(a); //100 // var a = 10; // let a = 100; // console.log(a); //Identifier 'a' has already been declared // let a = 10; // let a = 100; // let a = 10; // a = 100; // console.log(a); //100 //3、有着严格的作用域 // function fn(){ // var a = 'a'; // if(true){ //块级作用域 // let a = 'b' // }; // console.log(a) //'a' // }; // fn(); …… 阅读全文

前端提升1:JS

2025-03-01 16:56:47

摘要:一、JS数据结构 js的数据定义与检查 var str = 'abc'; var num = 123; var bool = true; var und = undefined; var n = null; var arr=['x','y','z']; var obj = {}; var fun = function() {}; console.log(typeof str); //string console.log(typeof num); //number console.log(typeof bool); //boolean console.log(typeof und); //undefined console.log(typeof n); //object console.log(typeof arr); //object console.log(typeof obj); //object console.log(typeof fun); //function 1. 字符串 window.onload = function () { // 字符串常用的属性和方法 // charAt() 方法可返回指定位置的字符。 // concat() 方法用于连接两个或多个字符串。 // indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。 // lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置 // includes() 方法用于判断字符串是否包含指定的子字符串 // replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串 // split() 方法用于把一个字符串分割成字符串数组 // substr() 方法可在字符串中抽取从开始下标开始的指定数目的字符 // substring() 方法用于提取字符串中介于两个指定下标之间的字符 // slice(start, end) 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分 // toLowerCase() 方法用于把字符串转换为小写 // toUpperCase() 方法用于把字…… 阅读全文

Dapr 完全离线安装方案

2024-09-01 23:15:28

摘要:Dapr 完全离线安装方案 以下是完整的 Dapr 离线安装指南,无需任何网络连接即可完成全部安装过程: 准备工作(在可联网的机器上) 1. 下载所有必需文件 # 创建离线安装目录 mkdir dapr-offline cd dapr-offline # 下载 Dapr CLI wget https://github.com/dapr/cli/releases/download/v1.15.0/dapr_linux_amd64.tar.gz # 下载 Dapr 运行时 wget https://github.com/dapr/dapr/releases/download/v1.15.5/daprd_linux_amd64.tar.gz # 下载 Dashboard wget https://github.com/dapr/dashboard/releases/download/v0.15.0/dashboard_linux_amd64.tar.gz # 下载默认配置文件 wget https://raw.githubusercontent.com/dapr/dapr/master/daprd-system/config.yaml 2. 下载 Docker 镜像并保存 # 拉取所需镜像 docker pull daprio/dapr:1.15.5 docker pull daprio/placement:1.15.5 docker pull daprio/sentry:1.15.5 docker pull daprio/dashboard:0.15.0 docker pull redis:6-alpine docker pull openzipkin/zipkin:latest # 保存镜像为 tar 文件 docker save -o dapr-1.15.5.tar daprio/dapr:1.15.5 docker save -o placement-1.15.5.tar daprio/placement:1.15.5 docker save -o sentry-1.15.5.tar daprio/sentry:1.15.5 docker save -o dashboard-0.15.0.tar daprio/dashboard:0.15.0 d…… 阅读全文

分布式架构之性能设计

2024-08-24 21:13:28

摘要:一、缓存 基本上来说,在分布式系统中最耗性能的地方就是最后端的数据库了。 一般来说,只要小心维护好,数据库四种操作(select、update、insert 和 delete)中的三个写操作 insert、update 和 delete 不太会出现性能问题(insert 一般不会有性能问题,update 和 delete 一般会有主键,所以也不会太慢)。除非索引建得太多,而数据库里的数据又太多,这三个操作才会变慢。 绝大多数情况下,select 是出现性能问题最大的地方。一方面,select 会有很多像 join、group、order、like 等这样丰富的语义,而这些语义是非常耗性能的;另一方面,大多数应用都是读多写少,所以加剧了慢查询的问题。 分布式系统中远程调用也会消耗很多资源,因为网络开销会导致整体的响应时间下降。为了挽救这样的性能开销,在业务允许的情况下,使用缓存是非常必要的事情。 缓存是提高性能最好的方式,一般来说,缓存有以下三种模式。 1. Cache Aside 更新模式 这是最常用的设计模式了,其具体逻辑如下。 失效:应用程序先从 Cache 取数据,如果没有得到,则从数据库中取数据,成功后,放到缓存中。 命中:应用程序从 Cache 中取数据,取到后返回。 更新:先把数据存到数据库中,成功后,再让缓存失效。 这是标准的设计模式,为什么不是写完数据库后更新缓存?主要是怕两个并发的写操作导致脏数据。 那么,是不是这个 Cache Aside 就不会有并发问题了?不是的。比如,一个是读操作,但是没有命中缓存,就会到数据库中取数据。而此时来了一个写操作,写完数据库后,让缓存失效,然后之前的那个读操作再把老的数据放进去,所以会造成脏数据。 这个案例理论上会出现,但实际上出现的概率可能非常低,因为这个条件需要发生在读缓存时缓存失效,而且有一个并发的写操作。实际上数据库的写操作会比读操作慢得多,而且还要锁表,读操作必须在写操作前进入数据库操作,又要晚于写操作更新缓存,所有这些条件都具备的概率并不大。 当然,最好还是为缓存设置好过期时间。 2. Read/Write Through 更新模式 在 Cache Aside 套路中,应用代码需要维护两个数据存储,一个是缓存,一个是数据库。所以,应用程序比较啰嗦。而 Read/Write Through 套路…… 阅读全文

分布式架构之管理设计

2024-08-17 18:04:48

摘要:一、分布式锁 我们知道,在多线程情况下访问一些共享资源需要加锁,不然就会出现数据被写乱的问题。在分布式系统下,这样的问题也是一样的。只不过,我们需要一个分布式的锁服务。 分布式的锁服务需要有以下几个特点。 安全性(Safety):在任意时刻,只有一个客户端可以获得锁(排他性)。 避免死锁:客户端最终一定可以获得锁,即使锁住某个资源的客户端在释放锁之前崩溃或者网络不可达。 容错性:只要锁服务集群中的大部分节点存活,Client 就可以进行加锁解锁操作。 1. Redis 的分布式锁服务 我们通过以下命令对资源加锁。 SET resource_name my_random_value NX PX 30000 解释一下: SET NX 命令只会在 key 不存在的时候给 key 赋值,PX 命令通知 Redis 保存这个 key 30000ms。 my_random_value 必须是全局唯一的值。这个随机数在释放锁时保证释放锁操作的安全性。 PX 操作后面的参数代表的是这个 key 的存活时间,称作锁过期时间。 当资源被锁定超过这个时间时,锁将自动释放。 获得锁的客户端如果没有在这个时间窗口内完成操作,就可能会有其他客户端获得锁,引起争用问题。 通过下面的脚本为申请成功的锁解锁: if redis.call(get,KEYS[1]) == ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end 如果 key 对应的 value 一致,则删除这个 key。通过这个方式释放锁是为了避免 Client 释放了其他 Client 申请的锁。 2. 分布式锁服务的一个问题 虽然 Redis 文档里说他们的分布式锁是没有问题的,但其实还是很有问题的。尤其是上面那个为了避免 Client 端把锁占住不释放,然后,Redis 在超时后把其释放掉,这事儿听起来就有点不靠谱。 我们来脑补一下,不难发现下面这个案例。 1. 如果 Client A 先取得了锁。 2. Client B 在等待 Client A 的工作完成。 3. 这个时候,如果 Client A 被挂在了某些事上,比如一个外部的阻塞调用,或是 CPU 被别的进程吃满,或是不巧碰上了 Full GC,导致 Client …… 阅读全文

分布式架构之弹力设计

2024-08-10 21:04:04

摘要:对于分布式系统的容错设计,在英文中又叫 Resiliency(弹力)。意思是,系统在不健康、不顺,甚至出错的情况下有能力 hold 得住,挺得住,还有能在这种逆境下力挽狂澜的能力。其中着眼于分布式系统的各种“容忍”能力,包括服务隔离、异步调用、请求幂等性、可伸缩性(有 / 无状态的服务)、一致性(补偿事务、重试)、应对大流量的能力(熔断、降级)。可以看到,在确保系统正确性的前提下,系统的可用性是弹力设计保障的重点。 我们很难计算我们设计的系统有多少的可用性,因为影响一个系统的因素实在是太多了,除了软件设计,还有硬件,还有第三方服务(如电信联通的宽带 SLA),当然包括“建筑施工队的挖掘机”,宕机原因主要有以下这些: 网络问题。网络链接出现问题,网络带宽出现拥塞…… 性能问题。数据库慢 SQL、Java Full GC、硬盘 IO 过大、CPU 飙高、内存不足…… 安全问题。被网络攻击,如 DDoS 等。 运维问题。系统总是在被更新和修改,架构也在不断地被调整,监控问题…… 管理问题。没有梳理出关键服务以及服务的依赖关系,运行信息没有和控制系统同步…… 硬件问题。硬盘损坏、网卡出问题、交换机出问题、机房掉电、挖掘机问题…… 一个分布式系统的故障是非常复杂的,因为故障是分布式的、多米诺骨牌式的。所以,要充分地意识到下面两个事。 故障是正常的,而且是常见的。 故障是不可预测突发的,而且相当难缠。 这就是为什么我们把这个设计叫做弹力(Resiliency)。 一方面,在好的情况下,这个事对于我们的用户和内部运维来说是完全透明的,系统自动修复不需要人的干预。 另一方面,如果修复不了,系统能够做自我保护,而不让事态变糟糕。 一、隔离设计 隔离设计对应的单词是 Bulkheads,中文翻译为隔板,这个概念来自于船舱里防漏水的隔板。我们的软件设计当然也“漏水”,所以为了不让“故障”蔓延开来,需要使用“隔板”技术,来将架构分隔成多个“船舱”来隔离故障。 1. 按服务的种类来做分离 上图中,我们将系统分成了用户、商品、社区三个板块。这三个块分别使用不同的域名、服务器和数据库,做到从接入层到应用层再到数据层三层完全隔离。这样一来,在物理上来说,一个板块的故障就不会影响到另一板块。 上面这种架构虽然在系统隔离上做得比较好,但是也存在以下一些问题。 如果我们需要同时获得多…… 阅读全文

分布式架构之本质

2024-08-03 11:55:30

摘要:我们一直在谈论各式各样的架构,如高并发架构、异地多活架构、容器化架构、微服务架构、高可用架构、弹性化架构等。还有和这些架构相关的管理型的技术方法,如 DevOps、应用监控、自动化运维、SOA 服务治理、去 IOE 等。面对这么多纷乱的技术,很多团队或是公司都是一个一个地去做这些技术,非常辛苦,也非常累。 接下来我们来谈一谈分布式架构。 一、概述 1. 分布式的优缺点 首先,为什么需要分布式系统,而不是传统的单体架构。 增大系统容量。我们的业务量越来越大,而要能应对越来越大的业务量,一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。 加强系统可用。我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。这样,整个系统不会因为一台机器出故障而导致整体不可用。所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。 当然,分布式系统还有一些优势,比如: 因为模块化,所以系统模块重用度更高; 因为软件服务模块被拆分,开发和发布速度可以并行而变得更快; 系统扩展性更高;团队协作流程也会得到改善; …… 不过,这个世界上不存在完美的技术方案,采用任何技术方案都是“按下葫芦浮起瓢”,都是有得有失,都是一种 trade-off。也就是说,分布式系统在解决上述问题的同时,也给我们带来了其他的问题。因此,我们需要清楚地知道分布式系统所带来的问题。 从上面的表格我们可以看到,分布式系统虽然有一些优势,但也存在一些问题。 架构设计变得复杂(尤其是其中的分布式事务)。 部署单个服务会比较快,但是如果一次部署需要多个服务,流程会变得复杂。 系统的吞吐量会变大,但是响应时间会变长。 运维复杂度会因为服务变多而变得很复杂。 架构复杂导致学习曲线变大。 测试和查错的复杂度增大。 技术多元化,这会带来维护和运维的复杂度。 管理分布式系统中的服务和调度变得困难和复杂。 2. 面向服务的架构有以下三个阶段 下面是一个 SOA 架构的演化图。 我们可以看到,面向服务的架构有以下三个阶段。 20 世纪 90 年代前,是单体架构,软件模块高度耦合。当然,这张图同样也说明了有的 SOA 架构其实和单体架构没什么两样,因为都是高度耦合在一起的。就像图中的齿轮一…… 阅读全文