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上添加方……
阅读全文
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中专门为组件提供的新属性。
创建组件实例,然后初……
阅读全文
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 ……
阅读全文
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();
……
阅读全文
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() 方法用于把字……
阅读全文
2024-09-21 21:03:17
摘要:一、安装Harbor
1. Harbor介绍
Harbor是由VMWare在Docker Registry的基础之上进行了二次封装,加进去了很多额外程序,而且提供了一个非常漂亮的web界面。
Project Harbor是一个开源的受信任的云本地注册表项目,用于存储、标记和扫描上下文。
Harbor扩展了开源Docker发行版,增加了用户通常需要的功能,如安全、身份和管理。
Harbor支持高级特性,如用户管理、访问控制、活动监视和实例之间的复制。
2. 功能
多租户内容签名和验证
安全性与漏洞分析
审计日志记录
身份集成和基于角色的访问控制
实例间的镜像复制
可扩展的API和图形UI
国际化(目前为英文和中文)
3. docker compose
Harbor在物理机上部署是非常难的,而为了简化Harbor的应用,Harbor官方直接把Harbor做成了在容器中运行的应用,而且这个容器在Harbor中依赖类似redis、mysql、pgsql等很多存储系统,所以它需要编排很多容器协同起来工作,因此VMWare Harbor在部署和使用时,需要借助于Docker的单机编排工具(Docker compose)来实现。
Compose是一个用于定义和运行多容器Docker应用程序的工具。使用Compose,我们可以使用YAML文件来配置应用程序的服务。然后,只需要一个命令,就可以从配置中创建并启动所有服务。
4. 部署
需要提前安装好docker
提前下载好安装包:Release v2.13.2 · goharbor/harbor · GitHub
安装docker-compose
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.39.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
docker comp……
阅读全文
2024-09-07 18:36:18
摘要:最近公司有个.net项目需要集群部署,由于不打算使用K8S,计划用docker swarm来搭建整个集群环境。
所以计划用2篇文章,记录一下docker swarm部署的整个过程。
文章使用的环境是本地虚拟机环境,生产环境大同小异。
文中用的到资料下载:docker-swarm.zip
一、安装 Docker
对于 Ubuntu/Debian 系统:
# 查看 ip
ip a
使用工具测试链接,如putty
# 1. 更新软件包索引
sudo apt-get update
# 2. 安装依赖包
sudo apt-get install ca-certificates curl gnupg lsb-release
# 3. 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 4. 设置稳定版仓库
echo deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null
# 5. 安装 Docker 引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 检查 Docker 版本
docker --version
对于 CentOS/RHEL 系统:
# 安装依赖包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加 Docker 仓库
sudo yum-config-manager --add-r……
阅读全文
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 ……
阅读全文