看作者讲这个知识点0F3F7FB7.png

https://www.bilibili.com/video/BV1rC4y187Vw?p=8

手动收集、手动触发

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>deps依赖收集</title>
  8. </head>
  9. <body>
  10. <script>
  11. let activeEffect
  12. class Dep {
  13. subsctibers = new Set()
  14. depend() {
  15. if (activeEffect) {
  16. this.subsctibers.add(activeEffect);
  17. }
  18. }
  19. notify() {
  20. this.subsctibers.forEach(effect => {
  21. effect()
  22. })
  23. }
  24. }
  25. function watchEffect(effect) {
  26. activeEffect = effect
  27. effect()
  28. activeEffect = null
  29. }
  30. const dep = new Dep()
  31. watchEffect(() => {
  32. dep.depend()
  33. console.log("effect run")
  34. }) // 这里会运行
  35. dep.notify() // 这里也会运行
  36. </script>
  37. </body>
  38. </html>

控制台打印

image.png

手动收集、手动触发、保存值

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>deps依赖收集</title>
  8. </head>
  9. <body>
  10. <script>
  11. let activeEffect
  12. // 此时不仅仅跟踪它的订阅者,而且保存一个值
  13. class Dep {
  14. subsctibers = new Set()
  15. constructor(value) {
  16. this.value = value
  17. }
  18. depend() {
  19. if (activeEffect) {
  20. this.subsctibers.add(activeEffect);
  21. }
  22. }
  23. notify() {
  24. this.subsctibers.forEach(effect => {
  25. effect()
  26. })
  27. }
  28. }
  29. function watchEffect(effect) {
  30. activeEffect = effect
  31. effect()
  32. activeEffect = null
  33. }
  34. const dep = new Dep("hello")
  35. watchEffect(() => {
  36. dep.depend()
  37. console.log(dep.value)
  38. }) // 这里会运行
  39. dep.value = "changed"
  40. dep.notify() // 这里也会运行
  41. </script>
  42. </body>
  43. </html>

控制台打印

image.png

自动收集、自动触发

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>deps依赖收集</title>
  8. </head>
  9. <body>
  10. <script>
  11. let activeEffect
  12. // 此时不仅仅跟踪它的订阅者,而且保存一个值
  13. class Dep {
  14. subsctibers = new Set()
  15. constructor(value) {
  16. this._value = value
  17. }
  18. set value(value) {
  19. this._value = value;
  20. // 当我们改变value时,会隐式调用notify
  21. this.notify() // 这里也会运行
  22. }
  23. get value() {
  24. // 当我们访问value,则会隐式调用depend
  25. this.depend()
  26. return this._value
  27. }
  28. depend() {
  29. if (activeEffect) {
  30. this.subsctibers.add(activeEffect);
  31. }
  32. }
  33. notify() {
  34. this.subsctibers.forEach(effect => {
  35. effect()
  36. })
  37. }
  38. }
  39. function watchEffect(effect) {
  40. activeEffect = effect
  41. effect()
  42. activeEffect = null
  43. }
  44. const dep = new Dep("hello")
  45. watchEffect(() => {
  46. console.log(dep.value)
  47. }) // 这里会运行
  48. dep.value = "changed"
  49. </script>
  50. </body>
  51. </html>

控制台打印

image.png

自动收集、自动触发、触发前清除依赖

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>deps依赖收集</title>
  8. </head>
  9. <body>
  10. <script src="./deps-value-autto-many.js"></script>
  11. </body>
  12. </html>
  1. let activeEffect
  2. let effectStack = []
  3. // 此时不仅仅跟踪它的订阅者,而且保存一个值
  4. class Dep {
  5. subsctibers = []
  6. constructor(value) {
  7. this._value = value
  8. }
  9. set value(value) {
  10. this._value = value;
  11. // 当我们改变value时,会隐式调用notify
  12. this.notify() // 这里也会运行
  13. }
  14. get value() {
  15. // 当我们访问value,则会隐式调用depend
  16. this.depend()
  17. return this._value
  18. }
  19. depend() {
  20. if (activeEffect) {
  21. this.subsctibers.push(activeEffect);
  22. this.subsctibers = Array.from(new Set(this.subsctibers))
  23. activeEffect.deps = this.subsctibers
  24. }
  25. }
  26. notify() {
  27. debugger;
  28. this.subsctibers.forEach(effect => {
  29. effect()
  30. })
  31. }
  32. }
  33. function watchEffect(fn) {
  34. const effect = createReactiveEffect(fn)
  35. return effect()
  36. }
  37. function createReactiveEffect(fn) {
  38. debugger;
  39. const effect = function reactiveEffect() {
  40. // 这里清除依赖
  41. cleanup(effect)
  42. activeEffect = effect
  43. fn()
  44. activeEffect = null
  45. }
  46. effect.deps = []
  47. return effect
  48. }
  49. function cleanup(effect) {
  50. const {
  51. deps
  52. } = effect
  53. if (deps.length) {
  54. deps.length = 0
  55. }
  56. }
  57. const msg = new Dep("hello")
  58. const ok = new Dep(true)
  59. watchEffect(() => {
  60. if (ok.value) {
  61. console.log(msg.value)
  62. } else {
  63. console.log("false branch")
  64. }
  65. }) // 这里会运行
  66. // msg.value = "changed"
  67. msg.value = "changed"
  68. console.log('-------------------')
  69. ok.value = false
  70. console.log('-------------------')
  71. msg.value = 'foo'
  72. console.log('-------------------')
  73. ok.value = true
  74. console.log('-------------------')
  75. msg.value = 'hello'
  76. console.log('-------------------')

控制台打印

image.png

其他

其中还有依赖嵌套问题,如何解决请看这篇文章
Vue3.0核心源码解读 | 响应式:响应式内部的实现原理是怎样的?(下)
这部分
image.png