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

邮箱网站架构/直销产业发展论坛

邮箱网站架构,直销产业发展论坛,做赌博网站犯法吗,360官网首页入口4.6 计算属性computed和lazy 懒执行的effect:一般的effect一下子就执行了,但是懒加载effect是等需要的时候才会执行 这时我们通过在options中添加lazy属性来达到目的 function effect (fn , options {}) {const effectFn () > {// 调用clearup函数…

4.6 计算属性computed和lazy

懒执行的effect:一般的effect一下子就执行了,但是懒加载effect是等需要的时候才会执行

这时我们通过在options中添加lazy属性来达到目的

  function effect (fn , options = {}) {const effectFn = () => {// 调用clearup函数完成清除工作clearUp(effectFn);activeEffect = effectFn; // 在调用副作用函数之前将副作用函数压入栈中effectStack.push(effectFn);fn();// 执行完之后抛出,把activeEffect还原成原来的值effectStack.pop();activeEffect = effectStack[effectStack.length - 1];}// 将options挂在到fn上effectFn.options = options;// deps用来存储所有与该副作用函数相关联的依赖集合effectFn.deps = [];// 只有非lazy的时候才会执行副作用函数if(!options.lazy){effectFn(); }return effectFn}

那什么时候才执行这个函数呢?

因为我们前面返回了effectFn作为effect函数的返回值,那我们就可以手动调用该副作用函数了

 const effectFn =  effect(() => {console.log(obj.foo);} ,// 添加lazy{lazy : true})// 手动执行副作用函数effectFn();obj.foo++;obj.foo++;

现在我们要实现假设传递给effect函数的是getter函数,可以返回getter函数的值

  const effectFn =  effect(() => {obj.foo + obj.bar} ,// 添加lazy{lazy : true})// 手动执行副作用函数const value = effectFn();console.log(value);

我们希望输出的是 obj.foo + obj.bar的值

实现computed函数

    // computed函数// 接收getter作为参数function computed (getter) {// 将gettwe作为副作用函数,创建一个lazy effectconst effectFn = effect( getter, {lazy : true})const obj = {// 对象的value是一个访问器属性// 只有当读取value的值时,才会执行effctFn并将其作为结果返回get value(){return effectFn()}}// 返回一个对象return obj;}// 开始使用计算属性const sumRes = computed(() => obj.foo + obj.bar)console.log(sumRes);//3

但是有一个bug。多次访问会导致effectFn多次计算

解决—对值进行缓存

    function computed (getter) {// value用来缓存let value// dirty标志,标识是否需要重新计算let dirty = true// 将gettwe作为副作用函数,创建一个lazy effectconst effectFn = effect( getter, {lazy : true})const obj = {// 对象的value是一个访问器属性// 只有当读取value的值时,才会执行effctFn并将其作为结果返回get value(){// 只有true时才可以进行计算if(dirty){value =  effectFn()// 将dirty设置为false,下一次直接使用缓存到value当中的值dirty = false;}return value}}// 返回一个对象return obj;}

无论我们执行了多少次sumRes都不会重新执行啦,直接取value里面的值

但是我们如果修改obj.foo的值,我们发现并没有响应的修改最后的sumRes

  get value(){// 只有true时才可以进行计算if(dirty){value =  effectFn()// 将dirty设置为false,下一次直接使用缓存到value当中的值dirty = false;}return value}

dirty = false;这便是原因

解决:当值发生变化的时候,改变dirty的值就可以啦,这时我们就要使用scheduler选项

    // computed函数// 接收getter作为参数function computed (getter) {// value用来缓存let value// dirty标志,标识是否需要重新计算let dirty = true// 将gettwe作为副作用函数,创建一个lazy effectconst effectFn = effect( getter, {lazy : true,scheduler(){dirty = true}})const obj = {// 对象的value是一个访问器属性// 只有当读取value的值时,才会执行effctFn并将其作为结果返回get value(){// 只有true时才可以进行计算if(dirty){value =  effectFn()// 将dirty设置为false,下一次直接使用缓存到value当中的值dirty = false;}return value}}// 返回一个对象return obj;}// 开始使用计算属性const sumRes = computed(() => obj.foo + obj.bar)console.log(sumRes.value);//4obj.foo++console.log(sumRes.value);//5

我们的计算属性已经趋于完美了,但是还有一个问题

   effect(() => {console.log(sumRes.value)})obj.foo++

我们希望的是在完成 obj.foo++之后是可以重新渲染的,但是我们发现并没有

其实这是一个典型的effect嵌套,一个计算属性的内部有effect,并且它是懒执行的,只有当真正读取计算属性的值才会执行。

  • 例如,假设我们有一个计算属性 fullName,它依赖于响应式数据 firstNamelastName。只有当我们读取 fullName 的值时,才会执行计算 fullNameeffect

但是getter里面访问的响应式数据只会把computed内部的effect收集为依赖。

而当把计算属性用于另一个effect时,就会发生effect嵌套,外层的effect不会被内层的effect所收集

  • 例如,假设我们有一个 effect 函数 updateUI,它读取 fullName。这时,updateUIeffectfullNameeffect 就会嵌套在一起。

解决—当读取计算属性的值时,我们可以手动调用track函数进行追踪,当计算属性发生变化的时候,手动调用trigger触发响应

  • 当读取计算属性的值时,手动调用 track 函数,将当前 effect(如 updateUI)添加到计算属性的依赖列表中。
  • 这样,当计算属性的依赖发生变化时,可以触发当前 effect
  • 当计算属性的值发生变化时,手动调用 trigger 函数,通知所有依赖该计算属性的 effect 进行更新。
  • 这样,外层的 effect(如 updateUI)会在计算属性(如 fullName)的依赖发生变化时被触发。

完整代码:

<script setup>let activeEffect;// effect栈const effectStack = [];function effect (fn , options = {}) {const effectFn = () => {// 调用clearup函数完成清除工作clearUp(effectFn);activeEffect = effectFn; // 在调用副作用函数之前将副作用函数压入栈中effectStack.push(effectFn);// 将effect的值存储起来const res =  fn();// 执行完之后抛出,把activeEffect还原成原来的值effectStack.pop();activeEffect = effectStack[effectStack.length - 1];// 返回resreturn res;}// 将options挂在到fn上effectFn.options = options;// deps用来存储所有与该副作用函数相关联的依赖集合effectFn.deps = [];// 只有非lazy的时候才会执行副作用函数if(!options.lazy){effectFn(); }return effectFn}const bucket = new WeakMap();const data = { foo : 2 , bar : 2 }; // 确保所有属性都已定义const obj = new Proxy(data, {get(target, key){track(target , key);return target[key];},set(target, key, newVal){target[key] = newVal;trigger(target , key , newVal);}});// 追踪变化function track(target , key){if(!activeEffect){return;}// 根据tartget取来的depsMap,它是一个map类型let depsMap = bucket.get(target);// 如果不存在if(!depsMap){// 创建一个bucket.set(target, (depsMap = new Map()));}// 根据key取来的deps,它是一个set类型let deps = depsMap.get(key);// 如果不存在if(!deps){// 创建一个depsMap.set(key, (deps = new Set()));}deps.add(activeEffect); // 添加当前活跃的副作用函数activeEffect.deps.push(deps);}
// 触发变化:处理调度逻辑function trigger(target, key, newVal) {const depsMap = bucket.get(target);if (!depsMap) {return;}const effects = depsMap.get(key);// 开始执行const effectsToRun = new Set(effects);effects && effects.forEach(effectFn => {if(activeEffect !== effectFn){effectsToRun.add(effectFn);}});effectsToRun.forEach(effectFn =>{if(effectFn.options.scheduler){effectFn.options.scheduler(effectFn);}else {effectFn();}});// effects && effects.forEach(fn => fn()); // 只触发与键相关的副作用函数}// 清除函数function clearUp (effectFn){// 遍历然后进行删除for(let i = 0 ; i < effectFn.deps.length ; i++){const deps = effectFn.deps[i];// 移除deps.delete(effectFn);}// 最后重置effectFn.deps数组effectFn.deps.length = 0;}//   effect(() => {//     console.log(obj.foo);//   })// obj.foo ++;//   obj.foo++;// 连续执行同一代码,只饭后最后一次计算的结果// 定义一个任务集合set:可以进行去重操作const jobQueue = new Set();// 使用promise.resolve()创建一个promise实例:将一个任务添加到微任务队列当中const p = Promise.resolve();// 开始刷新队列let isFlushing = false;function flushJob(){// 如果队列正在被刷新->returnif(isFlushing){return;}// 没有刷新,进行刷新操作isFlushing = true;p.then(() => {jobQueue.forEach(job => job());}).finally(() => {// 结束后重置isFlushing = false;})}// computed函数// 接收getter作为参数function computed (getter) {// value用来缓存let value// dirty标志,标识是否需要重新计算let dirty = true// 将gettwe作为副作用函数,创建一个lazy effectconst effectFn = effect( getter, {lazy : true,scheduler(){// 设置value进行triggertrigger(obj , 'value');dirty = true}})const obj = {// 对象的value是一个访问器属性// 只有当读取value的值时,才会执行effctFn并将其作为结果返回get value(){// 只有true时才可以进行计算if(dirty){value =  effectFn()// 将dirty设置为false,下一次直接使用缓存到value当中的值dirty = false;}// 读取value,进行追踪track(obj , 'value')return value}}// 返回一个对象return obj;}// 开始使用计算属性const sumRes = computed(() => obj.foo + obj.bar)console.log(sumRes.value);obj.foo++console.log(sumRes.value);effect(() => {console.log(sumRes.value)})obj.foo</script>

总结:

computed属性的实现我们首先用到了懒加载effect,需要使用的时候才使用。因为我们前面返回了effectFn作为effect函数的返回值,那我们就可以手动调用该副作用函数了。接着我们实现了computed属性,我们是传入一个getter函数和懒加载属性,为了解决多次访问会导致effectFn多次计算,我们需要缓存value。但是我们如果修改obj.foo的值,我们发现并没有响应的修改最后的sumRes,那是因为dirty并没有在修改值之后被修改为true,所以我们就要使用scheduler选项,在 effectoptions 中添加 scheduler,当计算属性的依赖发生变化时,将 dirty 设为 true,以便下次读取 value 时重新计算。为了解决effect嵌套的问题,我们进行了手动追踪和触发

http://www.whsansanxincailiao.cn/news/31962738.html

相关文章:

  • 图书馆网站建设所需资料/广州最新发布最新
  • 汽车4S店网站建设/四川二级站seo整站优化排名
  • 广西南宁网站公司/惠州网站seo排名优化
  • wordpress如何获取视频封面/沈阳百度推广优化
  • 找兼职工作在家做哪个网站好/杭州排名推广
  • 临沂在线做网站/抖音seo源码搭建
  • 创新的龙岗网站建设/相似图片在线查找
  • 如何做网商商城的网站/快速排名网站
  • 如何修改网站联系人/优化设计答案四年级上册语文
  • 如何建立一个公众号/seo优化 搜 盈seo公司
  • 站酷魔方网站建设中/武汉网络推广广告公司
  • 做点击率的网站/故事式软文范例100字
  • 网站建设人员架构/市场营销互联网营销
  • phpmysql网站开发/seo排名点击软件
  • 深圳移动官网网站建设/百度快照投诉
  • 有几家做网站的公司好/上海网站关键词排名
  • 电商网站建设存在的问题和处理方案/百度接单平台
  • WordPress 分类目录 加斜杠/西安网站seo服务
  • 广州app定制开发/泰安优化关键词排名哪家合适
  • 政法队伍建设网站主要内容/可以免费打开网站的软件
  • 三线建设学兵连网站西安地区联系人/seo优
  • 贵阳企业网站建设/营销网站系统
  • 业余学做衣服上哪个网站/搜索推广是什么意思
  • 医疗网站建设中心/sem优化
  • 太原百度推广制作个性商城网站/湖南营销型网站建设
  • 高大上的企业网站欣赏/优化大师在哪里
  • 如何创建网站主页/品牌推广平台
  • 做动态网站的用工具/百度首页关键词优化
  • 做企业网站可以没有后台吗/东莞网站推广及优化
  • 哈尔滨公司做网站/营销案例100例简短