Vue3响应式系统(二)

这篇具有很好参考价值的文章主要介绍了Vue3响应式系统(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Vue3响应式系统(一)https://blog.csdn.net/qq_55806761/article/details/135587077

六、嵌套的effect与effect栈。

        什么场景会用到effect嵌套呢?听我娓娓道来。

        就用Vue.js来说吧,Vue.js的渲染函数就是在effect中执行的:

/*Foo组件*/
const Foo = {
    render() {
        return /*.....*/
    }
}


// effect中执行Foo组件中的渲染函数
effect(() => {
    Foo.render()
})

        当组件发生嵌套的时候,渲染的时候effect函数中就会发生effect嵌套。

//Bar组件
const Bar = {
  render() {/* ... */}
}
const Foo = {
  render() {
    return <Bar />
  }
}

//effect执行的时候就会发生嵌套
effect(() => {
  Foo.render()
  effect(() => {
    Bar.render()
  })
})

        所以,目前并不能支持effect嵌套,我们用之前的代码来测试一下:

//原始数据
const data = {
  ok: true,
  text: 'hello world'
}
// WeakMap桶
const bucketMap = new WeakMap()
//用全局变量存储被注册的副作用函数
let activeEffect

function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    fn()
  }
  // deps用来存储所有与这副作用函数相关联的依赖集合
  effectFn.deps = []
  effectFn()
}
const obj = new Proxy(data, {
  get(target, key) {
    // 注册副作用函数
    track(target, key)
    return target[key]
  },
  set(target, key, newVal) {
    target[key] = newVal
    // 触发副作用函数
    trigger(target, key)
    return true
  }
})
function cleanup(effectFn) {
  //遍历effectFn的deps数组
  for(let i = 0; i < effectFn.deps.length; i++) {
    let deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  // 最后需要重置effectFn.deps数组
  effectFn.deps.length = 0
}
function trigger(target, key) {
  // 取target
  const depsMap = bucketMap.get(target)
  if (!depsMap) return
  // 根据key取副作用函数
  const effects = depsMap.get(key)
  // 执行副作用函数
  const effectToRun = new Set(effects)
  effectToRun && effectToRun.forEach(fn => fn())
}
function track(target, key) {
  // 没有activeEffect直接返回
  if (!activeEffect) return target[key]
  // 取出WeakMap桶里的值 target ===> key
  let depsMap = bucketMap.get(target)
  // 如果不存在depsMap,那就新建Map与target建立联系
  if (!depsMap) {
    bucketMap.set(target, (depsMap = new Map()))
  }
  // key ===> effectFn
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, deps = new Set())
  }
  // 注册副作用函数
  deps.add(activeEffect)
  // ======= 主要就是增加关联数组中 ===========
  activeEffect.deps.push(deps)
}

let temp1, temp2
effect(function effectFn1() {
  console.log('effectFn1执行')
  effect(function effectFn2() {
    console.log('effectFn2执行');
    temp2 = obj.ok
  })
  temp1 = obj.text
})
obj.text = 'Vue3'

 Vue3响应式系统(二),前端工程师,vue.js,前端,javascript

        出现问题了,当我们修改text的值的时候,我们希望的是触发effectFn1,而现在是触发effectFn2,并没有执行effectFn1。

       问题在哪里呢?

        我们用全局变量activeEffect来存储通过effect函数注册的副作用函数,意味着同一时刻activeEffect所存储的副作用函数只能有一个。当副作用函数发生嵌套时,内层副作用函数会覆盖activeEffect,并且永远不会恢复,即使响应式数据是在外层副作用函数中读取的,他们收集到的副作用函数也都会是内层副作用函数,这个就是问题所在。

        为了解决这个问题,我们需要一个副作用函数栈effectStack,在副作用函数执行的时候,将当前副作用函数压入栈中,执行完毕后将副作用函数弹出,activeEffect始终指向栈顶的副作用函数。这样便不会出现相互影响的情况了。

       增加副作用函数栈

//用全局变量存储被注册的副作用函数
let activeEffect
// effectStack栈
let effectStack = []
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    effectStack.push(effectFn)
    fn()
    effectStack.pop()
    activeEffect = effectStack[effectStack.length - 1]
  }
  // deps用来存储所有与这副作用函数相关联的依赖集合
  effectFn.deps = []
  effectFn()
}

        完整代码:

//原始数据
const data = {
  ok: true,
  text: 'hello world'
}
// WeakMap桶
const bucketMap = new WeakMap()
//用全局变量存储被注册的副作用函数
let activeEffect
// effectStack栈
let effectStack = []
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    effectStack.push(effectFn)
    fn()
    effectStack.pop()
    activeEffect = effectStack[effectStack.length - 1]
  }
  // deps用来存储所有与这副作用函数相关联的依赖集合
  effectFn.deps = []
  effectFn()
}
const obj = new Proxy(data, {
  get(target, key) {
    // 注册副作用函数
    track(target, key)
    return target[key]
  },
  set(target, key, newVal) {
    target[key] = newVal
    // 触发副作用函数
    trigger(target, key)
    return true
  }
})
function cleanup(effectFn) {
  //遍历effectFn的deps数组
  for(let i = 0; i < effectFn.deps.length; i++) {
    let deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  // 最后需要重置effectFn.deps数组
  effectFn.deps.length = 0
}
function trigger(target, key) {
  // 取target
  const depsMap = bucketMap.get(target)
  if (!depsMap) return
  // 根据key取副作用函数
  const effects = depsMap.get(key)
  // 执行副作用函数
  const effectToRun = new Set(effects)
  effectToRun && effectToRun.forEach(effectFn => effectFn())
}
function track(target, key) {
  // 没有activeEffect直接返回
  if (!activeEffect) return target[key]
  // 取出WeakMap桶里的值 target ===> key
  let depsMap = bucketMap.get(target)
  // 如果不存在depsMap,那就新建Map与target建立联系
  if (!depsMap) {
    bucketMap.set(target, (depsMap = new Map()))
  }
  // key ===> effectFn
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, deps = new Set())
  }
  // 注册副作用函数
  deps.add(activeEffect)
  // ======= 主要就是增加关联数组中 ===========
  activeEffect.deps.push(deps)
}

let temp1, temp2
effect(function effectFn1() {
  debugger
  console.log('effectFn1执行')
  effect(function effectFn2() {
    console.log('effectFn2执行');
    temp2 = obj.ok
  })
  temp1 = obj.text
})
obj.text = 'Vue3'

        Vue3响应式系统(二),前端工程师,vue.js,前端,javascript

        这样便达到预期!! 

Vue3响应式系统(三)https://blog.csdn.net/qq_55806761/article/details/135635322文章来源地址https://www.toymoban.com/news/detail-809270.html

到了这里,关于Vue3响应式系统(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端工程师如何突破瓶颈期

    前端工程师在职业生涯中可能会遇到瓶颈期,这时需要有一定的策略和方法来突破,以下是一些建议: 持续学习:前端技术更新换代非常快,需要不断学习新技术和新知识,保持自己的竞争力。 扩展技能:在掌握核心技能的基础上,可以扩展自己的技能范围,例如学习后端

    2024年02月06日
    浏览(47)
  • 成为一名高级前端开发工程师

    前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库  web前端面试题库 VS java后端面试题库大全 随着互联网技术的不断发展,前端开发已经成为了一项非常重要的职业。如果您希望成为一名高级前端开发工程师,那么以下几点建议可能会对您有所帮助。 1

    2024年02月12日
    浏览(55)
  • 一名【合格】前端工程师的自检清单

    前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快是其他技术所不能比拟的。 winter 在他的《重学前端》课程中提到: 到现在为止,前端工程师已经成为研发体系中的重要岗位之一。可是,与此相对的是,我发现极少或者几乎没

    2024年02月08日
    浏览(61)
  • 浅谈ChatGPT取代前端开发工程师

    1.ChatGPT 是什么? ChatGPT 是一种基于深度学习的自然语言处理技术,它可以生成高质量的自然语言文本。该技术是由 OpenAI 团队 开发,旨在使计算机能够像人类一样理解和产生自然语言。ChatGPT 使用了深度神经网络和自然语言处理技术,通 过对大量语言数据的学习和建模,实现

    2023年04月08日
    浏览(42)
  • 81.一名【合格】前端工程师的自检清单

    前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快是其他技术所不能比拟的。 winter 在他的《重学前端》课程中提到: 到现在为止,前端工程师已经成为研发体系中的重要岗位之一。可是,与此相对的是,我发现极少或者几乎没

    2024年02月08日
    浏览(40)
  • AI 入侵前端,哪类工程师最危险?

    随着人工智能技术的不断发展,越来越多的企业开始将 AI 技术应用于产品和服务中。在前端领域,AI 技术也开始逐渐渗透进来。然而,这种技术革新也给前端工程师们带来了新的挑战。那么,在 AI 入侵前端的时代,哪类工程师最危险呢?本文将对此进行分析。 正文: 1. 前端

    2024年02月03日
    浏览(37)
  • 前端浏览器缓存知识梳理,前端工程师面试题目和答案

    所谓浏览器缓存其实就是指在本地使用的计算机中开辟一个内存区,同时也开辟一个硬盘区作为数据传输的缓冲区,然后用这个缓冲区来暂时保存用户以前访问过的信息。 浏览器缓存过程:  强缓存,协商缓存。 浏览器缓存位置一般分为四类:  Service Worker–Memory Cache–Di

    2024年04月15日
    浏览(52)
  • 高级web前端开发工程师的职责说明(合集)

      高级web前端开发工程师的职责说明1 职责: 1、根据需求文档,完成PC端、移动端页面及交互的开发,并保证兼容性和确保产品具有优质的用户体验; 2、熟练使用 HTML 、 CSS 、 JS 、 Ajax 等技术,能解决各种浏览器兼容性问题,完成页面架构和布局; 3、熟练编写结构良好,语义

    2024年02月14日
    浏览(45)
  • 前端Vue篇之Vue3响应式:Ref和Reactive

    在Vue3中,响应式编程是非常重要的概念,其中 Ref 和 Reactive 是两个关键的API。 Ref : Ref 用于创建一个响应式的基本数据类型,比如数字、字符串等。它将普通的数据变成响应式数据,可以监听数据的变化。使用 Ref 时,我们可以通过 .value 来访问和修改数据的值。 Reactive :

    2024年04月25日
    浏览(50)
  • 全栈工程师必须要掌握的前端CSS技能

    作为一名全栈工程师,在日常的工作中,可能更侧重于后端开发,如:C#,Java,SQL ,Python等,对前端的知识则不太精通。在一些比较完善的公司或者项目中,一般会搭配前端工程师,UI工程师等,来弥补后端开发的一些前端经验技能上的不足。但并非所有的项目都会有专职前

    2024年02月09日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包