当前位置: 首页 > news >正文

在线logo知名seo网站优化

在线logo,知名seo网站优化,wordpress 主题 lin,网站建设 报价单从高层设计的角度去探讨框架需要关注的问题。 系列目录#xff1a; 标题博客第一篇#xff1a;框架设计概览【Vue.js设计与实现】第一篇#xff1a;框架设计概览-阅读笔记第二篇#xff1a;响应系统【Vue.js设计与实现】第二篇#xff1a;响应系统-阅读笔记第三篇#x… 从高层设计的角度去探讨框架需要关注的问题。 系列目录 标题博客第一篇框架设计概览【Vue.js设计与实现】第一篇框架设计概览-阅读笔记第二篇响应系统【Vue.js设计与实现】第二篇响应系统-阅读笔记第三篇渲染器【Vue.js设计与实现】第三篇渲染器-阅读笔记第四篇组件化【Vue.js设计与实现】第四篇组件化-阅读笔记第五篇编译器【Vue.js设计与实现】第五篇编译器-阅读笔记第六篇服务端渲染【Vue.js设计与实现】第六篇服务端渲染-阅读笔记 第二篇 响应系统 第 4 章 响应系统的作用与实现第 5 章 非原始值的响应式方案第 6 章 原始值的响应式方案 文章目录 第四章响应系统的作用与实现4.1 响应式数据与副作用函数4.2 响应式数据的基本实现4.3 设计一个完善的响应系统4.4 分支切换与 cleanup4.5 嵌套的 effect 与 effect 栈4.6 避免无限递归循环4.7 调度执行其他响应式数据调度系统计算属性懒惰执行watch的实现原理过期的副作用 第七章渲染器的设计第八章挂载与更新DOM节点操作属性节点操作事件 第四章响应系统的作用与实现 4.1 响应式数据与副作用函数 副作用函数即会产生副作用的函数。 如effect 函数的执行会直接或间接影响其他函数的执行如修改了全局变量它就是一个副作用函数。 function effect() {document.body.innerHTML obj.text; }响应式数据若obj.text变化了我们希望副作用函数effect 重新执行如果能实现这个目标就是响应式。 const obj { text: hello world };function effect() {document.body.innerHTML obj.text; }4.2 响应式数据的基本实现 如何让obj实现响应式我们发现 当副作用函数 effect 执行时会触发字段 obj.text 的读取操作当修改 obj.text 的值时会触发字段 obj.text 的设置操作 也就是说我们可以通过拦截一个对象的读取和设置操作来实现响应式 设置一个桶来存放与响应式数据相关的副作用函数读取数据时把与这个响应式数据相关的副作用函数放进一个桶里设置数据时即修改数据时桶里所有的函数都是与这个响应式数据相关的函数因此 执行桶中所有函数 拦截一个对象属性的读取和设置操作在vue2用Object.defineProperty实现在vue3用代理对象Proxy实现。 我们根据上述思路简单地用proxy实现响应式数据 桶与响应式数据 // 存储副作用函数的桶 const bucket new Set();// 原始数据 const data { text: hello world }; // 对原始数据的代理 const obj new Proxy(data, {// 拦截读取操作get(target, key) {// 将副作用函数 effect 添加到存储副作用函数的桶中bucket.add(effect);// 返回属性值return target[key];},// 拦截设置操作set(target, key, newVal) {// 设置属性值target[key] newVal;// 把副作用函数从桶里取出并执行bucket.forEach((fn) fn());// 操作成功return true;}, });具体调用 // 副作用函数 function effect() {document.body.innerHTML obj.text; }// 执行副作用函数触发读取 effect();// 1 秒后修改响应式数据 setTimeout(() {obj.text hello vue3; }, 1000);在浏览器中运行可以看到字符串的闪动。 4.3 设计一个完善的响应系统 由上一节可知一个响应系统的工作流程如下 当读取操作发生时将副作用函数收集到“桶”中当设置操作发生时从“桶”中取出副作用函数并执行 但是上一节的操作有些缺陷我们硬编码了副作用函数的名字effect导致一旦副作用函数的名字不叫 effect那么这段代码就不能正确地工作了。我们希望哪怕副作用函数是一个匿名函数也能够被正确地收集到“桶”中。因此我们需要提供用来注册副作用函数的机制。 // 用一个全局变量存储被注册的副作用函数 let activeEffect;// effect 函数用于注册副作用函数 function effect(fn) {activeEffect fn;fn(); }这样一来就可以使用一个匿名的副作用函数作为 effect 函数的参数。 响应系统就不依赖副作用函数的名字了。 const obj new Proxy(data, {get(target, key) {// 新增if(activeEffect){bucket.add(activeEffect)}return target[key];},set(target, key, newVal) {target[key] newVal;bucket.forEach((fn) fn());return true;}, });然而上述代码还有缺陷假设我们给obj的其他字段赋值也会触发proxy的set这是不对的我们的初衷是只obj.text有响应式。这个问题的根本原因没有在副作用函数与被操作的目标字段之间建立明确的联系。 解决方法重新设计“桶”的数据结构。 观察下面代码 function effect() {document.body.innerHTML obj.text; }此副作用函数中有3个角色 被读取的代理对象obj被读取的字段text副作用函数effect 如果用 target 来表示一个代理对象所代理的原始对象用 key 来表示被操作的字段名用 effectFn 来表示被注册的副作用函数则他们的数据结构为树形数据结构关系如下 target-- key--effectFn举个例子 两个副作用函数同时读取同一个对象的属性值 target-- key--effectFn1--effectFn2一个副作用函数中读取了一个对象的两个属性 target-- key1--effectFn-- key2--effectFn不同的副作用函数中读取了两个不同对象的不同属性 target1-- key1--effectFn1target2-- key2--effectFn2构建数据结构与代码 桶WeakMap 由 target -- Map 构成桶里的target Map 由 key -- Set 构成 const bucket new WeakMap();const obj new Proxy(data, {get(target, key) {if (!activeEffect) return target[key];// key - effectslet depsMap bucket.get(target);if (!depsMap) {bucket.set(target, (depsMap new Map()));}// deps 存储所有与[target,key]相关的副作用函数let deps depsMap.get(key);if (!deps) {depsMap.set(key, (deps new Set()));}deps.add(activeEffect);return target[key];},set(target, key, newVal) {target[key] newVal;const depsMap bucket.get(target);if (!depsMap) return;const effects depsMap.get(key);effects effects.forEach((effect) effect());}, }); WeakMap 的键是原始对象 targetWeakMap 的值是一个Map 实例而 Map 的键是原始对象 target 的 keyMap 的值是一个由副作用函数组成的 Set。 我们把下图中 Set 数据结构所存储的副作用函数集合称为 key 的依赖集合 为什么桶要使用WeakMap const map new Map(); const weakMap new WeakMap()(function () {const foo { foo: 1 };const bar { bar: 2 };map.set(foo, 1);weakMap.set(bar, 2); })()上述代码定义了一个立即执行的函数表达式IIFE当它执行完时map的key 强引用 foo则它不会被垃圾回收器回收而WeakMap的 key 是弱引用垃圾回收器就会把对象 bar 从内存中移除。 简单地说WeakMap 对 key 是弱引用不影响垃圾回收器的工作。 常用于存储那些只有当 key 所引用的对象存在时没有被回收才有价值的信息如上述场景若 target 对象没有引用了说明用户不需要它了此时垃圾回收器会完成回收任务。 如果使用 Map 来代替 WeakMap 那么即使用户的代码对 target 没有任何引用这个 target 也不会被回收最终可能导致内存溢出。 最后把收集、触发副作用函数封装到track、trigger中 const bucket new WeakMap();const obj new Proxy(data, {get(target, key) {track(target, key);return target[key];},set(target, key, newVal) {target[key] newVal;trigger(target, key)}, });function track(target, key) {if (!activeEffect) return;let depsMap bucket.get(target);if (!depsMap) {bucket.set(target, (depsMap new Map()));}let deps depsMap.get(key);if (!deps) {depsMap.set(key, (deps new Set()));}deps.add(activeEffect); }function trigger(target, key) {const depsMap bucket.get(target);if (!depsMap) return;const effects depsMap.get(key);effects effects.forEach((effect) effect()); } 4.4 分支切换与 cleanup 分支切换当字段 obj.ok 的值发生变化时代码执行的分支会跟着变化这就是分支切换 document.body.innerHTML obj.ok ? obj.text : not;分支切换可能会产生遗留的副作用函数。obj.ok的初始值为true时会读取字段obj.text则副作用函数与响应式数据之间的联系如下 data--ok--effectFn--text--effectFn 当obj.ok的值为false时obj.text不会被读取此时副作 用函数 effectFn 不应该被字段 obj.text 所对应的依赖集合收集 然而在obj.ok改为false时我们并没有删除key为text的副作用函数这就产生了遗留的副作用函数。 遗留的副作用函数会导致不必要的更新。即会调用不必要的副作用函数。举个例子 effect(function effectFn(){document.body.innerHTML obj.ok ? obj.text : not; })若此时obj.ok为false但修改了obj.text的值副作用函数仍然会执行尽管我们已经不再读取obj.text了。 解决这个问题的方法每次副作用函数执行时我们可以 先把它从所有与之关联的依赖集合中删除。当副作用函数执行完毕后会重新建立联系但在新的联系中不会包含遗留的副作用函数。如图 要将一个副作用函数从所有与之关联的依赖集合中移除就需要知道哪些依赖集合中包含它即需要一个数组来存储包含当前副作用函数的依赖集合。 给effectFn 添加一个属性deps 用来存储会调用此副作用函数的依赖集合。 function effect(fn) {const effectFn () {activeEffect effect;fn();};// 存储所有与该副作用函数相关联的依赖集合effectFn.deps [];effectFn(); }在track中添加 function track(target, key) {if (!activeEffect) return;let depsMap bucket.get(target);if (!depsMap) {bucket.set(target, (depsMap new Map()));}let deps depsMap.get(key);if (!deps) {depsMap.set(key, (deps new Set()));}deps.add(activeEffect);// 新增activeEffect.deps.push(deps); }在副作用函数执行时将包含此副作用函数的依赖集合中的此函数移除 function effect(fn) {const effectFn () {// 调用 cleanup 函数完成清除工作cleanup(effectFn);activeEffect effect;fn();};// 存储所有与该副作用函数相关联的依赖集合effectFn.deps [];effectFn(); }function cleanup(effectFn) {for (let i 0; i effectFn.deps.length; i) {const deps effectFn.deps[i];deps.delete(effectFn);}// 重置数组effectFn.deps.length 0; }到这里我们已经清除了遗留的副作用函数。然而运行此代码会发现出现了死循环。问题出现在trigger 函数中 function trigger(target, key) {const depsMap bucket.get(target);if (!depsMap) return;const effects depsMap.get(key);// 问题出现在这里effects effects.forEach((effect) effect()); }原因 在调用 forEach 遍历 Set 集合时如果一个值已经被访问过了但该值被删除并重新添加到集合如果此时 forEach 遍历没有结束那么该值会重新被访问 因此想要解决这个问题我们可以创建一个新的set集合并遍历它 function trigger(target, key) {const depsMap bucket.get(target);if (!depsMap) return;const effects depsMap.get(key);// 新增const effectsToRun new Set(effects);effectsToRun.forEach((effect) effect()); }4.5 嵌套的 effect 与 effect 栈 上述代码在effect嵌套时会出错原因是 同一时刻 activeEffect 所存储的副作用函数只能有一个。当副作用函数发生嵌套时内层副作用函数的执行会覆盖 activeEffect 的值并且永远不会恢复到原来的值。 解决方法需要一个副作用函数栈 effectStack在副作用函数执行时将当前副作用函数压入栈中执行完毕后将其从栈中弹出并始终让 activeEffect 指向栈顶的副作用函数。 let activeEffect; const effectStack [];function effect(fn) {const effectFn () {cleanup(effectFn);activeEffect effectFn;effectStack.push(effectFn);fn();effectStack.pop();activeEffect effectStack[effectStack.length - 1];};effectFn.deps [];effectFn(); }4.6 避免无限递归循环 如下代码会无限递归循环 const data { foo: 1 }; const obj new Proxy(data, {// });effect(() obj.foo);原因是obj.foo语句会读取也会设置因此它会触发track和trigger不断地添加副作用函数。 解决方法可以在 trigger 动作发生时增加守卫条件如果 trigger 触发执行的副作用函数与当前正在执行的副作用函数相同则不触发执行。 function trigger(target, key) {const depsMap bucket.get(target);if (!depsMap) return;const effects depsMap.get(key);// 新增const effectsToRun new Set();effects effects.forEach((effect) {if (effect ! activeEffect) {effectsToRun.add(effect);}});effectsToRun.forEach((effect) effect()); }4.7 调度执行 其他 响应式数据 先了解两个概念副作用函数和响应式数据。 副作用函数会产生副作用的函数。 如 let val1function effect(){val2 }这个函数改变了全局变量val产生了副作用因此是副作用函数。 而如果val这个数据的变化改变了视图的变化那么val就称作响应式数据。 想要实现响应式数据需要依赖两个行为 getter数据读取setter数据修改 vue2中这两个行为通过Object.defineProperty实现 vue3中这两个行为通过Proxy实现。 响应式数据的实现原理 Vue在组件和实例初始化的时候会将data里的数据进行数据劫持即Object.defineProperty对数据进行处理。被劫持后的数据会有两个属性getter和setter。 使用数据时触发getter修改数据时触发setter同时也出发了底层的watcher监听通知DOM修改刷新。 这就实现了响应式数据。 Vue中的数据变页面一定变吗 不一定。数据变页面也变是因为数据有getter和setter两个属性。如果没有则不会变。 vue中的响应式是什么? 怎么理解响应式原理?_vue响应式属性_J.P_P的博客-CSDN博客 Vue 核心之数据劫持 - Jaye8584 - 博客园 (cnblogs.com) 调度系统 调度系统指的是响应性的可调度性。 可调度性指的是当数据更新的动作触发副作用函数重新执行时有能力决定副作用函数effect执行的时机、次数以及方式。 想要实现一个调度系统需要依赖异步Promise和队列jobQueue。需要基于Set构建出一个基本的队列数组jobQueue利用Promise的异步特性来控制执行的顺序。 计算属性 计算属性的本质一个属性值当依赖响应式数据发生变化时重新计算。 计算属性的实现依赖于调度系统。 懒惰执行 watch监听器观测一个响应式数据当数据发生变化时通知并执行对应的回调函数。 这意味着watch很多时候不需要立即执行。因此需要懒惰执行进行控制。 懒惰执行的实现比调度系统简单。本质上是一个boolean型的值被添加到effet函数中用来控制副作用的执行。 if(!lazy){//执行副作用函数 }watch的实现原理 基于调度系统和懒惰执行。 过期的副作用 我们可以在watch完成异步操作。但是大量的异步操作可能导致竞态问题。 竞态问题在描述一个系统或进程的输出依赖于不受控制的事件出现顺序或者出现时机。 如 let findDatawatch(obj,async(){const resawait fetch(/path/to/request)findDatares })这段代码是异步操作。若obj改变了两次就会发送两次网络请求。我们无法知道findData最后保存的值是哪一次网络请求的。这种问题就是竞态问题。 而如果想要解决这问题那么就需要使用到 watch 回调函数的第三个参数 onInvalidate它本身也是一个回调函数。并且该回调函数onInvalidate会在副作用下一次重新执行前调用可以用来清除无效的副作用例如等待中的异步请求 而onInvalidate 的实现原理也非常简单只需要 在副作用函数effct重新执行前先触发 onInvalidate 即可。 好抽象没太懂。 第七章渲染器的设计 渲染器和渲染函数不是一个东西。 渲染器是createRenderer的返回值是一个对象渲染函数是渲染器对象中的render方法 在vue 3.2.37 源码中createRenderer函数具体是通过baseCreateRenderer进行的。总体可以分为两部分 在浏览器端渲染时利用DOM API完成DOM操作如渲染DOM用createElement删除DOM使用removeChild渲染器不能和宿主环境浏览器强耦合vue中有浏览器渲染和服务端渲染。若与浏览器强耦合就不好实现服务端渲染了。 vnode 是一个普通的JS对象代表了渲染的内容。 对象中通过type表示渲染的DOM。如typediv表示div标签。typeFragment表示文档片段。 第八章挂载与更新 对于渲染器它所作的最核心的事情是对节点进行挂载、更新。 第八章分为两部分来讲解这件事 DOM节点操作属性节点操作 DOM节点操作 分为3部分 挂载节点的初次渲染。如用createElement新建一个节点。更新当响应性数据发生变化时可能会涉及到DOM的更新。本质上属于属性的更新。卸载旧节点不再需要了就删除旧节点。如通过parentEl.removeChild进行。 属性节点操作 属性可以分为两类 属性如classidvalue…事件如click、input… 先了解非事件的属性部分。 想了解vue对属性的处理需要先了解浏览器中的属性分类。 浏览器中DOM属性被分为两类 HTML Attributes直接定义在HTML上的属性DOM Properties拿到DOM对象后定义的属性。 对于HTML Attributes它只能在html中操作。而想要在JS中操作DOM需要通过DOM Properties来实现。因为JS本身特性的问题会导致某些DOM Properties的设置存在特殊性如class、type、value。为了保证DOM Properties的成功设置我们需要知道不同属性的DOM Properties定义方式。 el.setAttribute(属性名,属性值). 属性赋值el.属性名属性值 或 el[属性名]属性值 事件
http://www.pierceye.com/news/730855/

相关文章:

  • 福州微网站开发什么样的网站快速盈利
  • 吉首市建设局官方网站一对一直播软件开发定制
  • 网站开发验收单做的网站如何被百度搜到
  • 网站的数据库是什么两学一做网站链接
  • 做窗帘网站济南网络科技公司排名
  • 广东省住房城乡建设部网站哪个网站可以做加工代理的
  • dede网站源码打包下载wordpress登不进后台
  • 建设内部网站目的国内贸易在那个网站上做
  • 用什么建设网站注册深圳公司代理
  • 网站平台建设方案书百度云资源搜索入口
  • 网站 团队博罗网站建设哪家便宜
  • wordpress列表分页枣庄seo外包
  • 知了网站后台推广形式有哪几种
  • 成品图片的网站在哪里找wordpress开启防盗链
  • 伊滨区网站建设网站建设经理
  • 权威的郑州网站建设域名租用平台
  • 造价工程师网网站点击排名优化
  • 网站关键词搜索海口网站建设优化公司
  • WordPress建影视站免费的素材网站有哪些
  • 屯留做网站哪里好阿里云服务器618
  • 网站怎么做登录模块免费的编程软件下载
  • 网站建设与管理的策划书网站建设五合一
  • 网站建设管理分工公司招聘网站有哪些
  • 分类信息网站手机版上海网站关键词优化方法
  • 建设个人网站的参考网站及文献怎么做水果网站
  • 台山住房和城乡建设 网站有赞分销
  • 网站备案 历史wordpress货币插件
  • 如何做自助搜券网站佛山顺德专业做网站
  • 义乌网站制作多少钱工会网站建设
  • 六安高端网站建设公司开网店的流程步骤