11

了解 vue composition-api 原理

 3 years ago
source link: https://shenzilong.cn/record/%E6%AF%8F%E6%97%A5%E6%80%BB%E7%BB%93/2021/doc/%E4%BA%86%E8%A7%A3%20vue%20composition-api%20%E5%8E%9F%E7%90%86.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

了解 vue composition-api 原理

写在前面的心得

  1. 1.

    不要在 setup 内直接使用 setInterval 与 setTimeout 这类需要手动清理副作用的 api

    1. 1.

      因为人很容易忘记清理他的副作用,应该自行封装一个类似于计算属性的

watch

我对 composition-api 中的 watch 的实现一直很好奇,它到底怎么知道我里面依赖了哪些变量?

例如下面的代码:

import {watchEffect, ref } from "vue"
const msg = ref("后撤步!")
watchEffect(()=>{
  console.log(msg.value)
})
setTimeout(()=>{
    msg.value = "7777"
},1000)

虽然用了这么久的 composition-api 但我从来都不明白 watchEffect 到底是怎么知道 cb 依赖了 msg 的

我自己猜想的方式有两种:

  • 第一种是直接执行一遍 cb, msg 的 getter 内就能知道 cb 依赖了 msg,但 cb 内如果有 if 之类的逻辑就会漏掉一些变量的依赖

    const t = Date.now()
    watchEffect(()=>{
      if(Date.now() - t > 500){
        console.log(msg.value) // 永远不会被执行
      }
      setTimeout(()=>{
        console.log(msg.value) // 只会被执行一次
      },10)
    })
    setTimeout(()=>{
        msg.value = "7777"
    },1000)
    

    像这样的代码在 1000ms 后并不会打印 msg.value

  • 另一种是获取 cb 的源码来进行分析,执行 cb.toString() 得到 ()=>{ console.log(msg) } 就可以看到里面依赖了 msg ,但如果将 cb 改一下

    const a = ()=>{
      console.log(msg)
    }
    const cb = ()=>{
      a()
    } 
    

    这时候 cb.toString() 得到的是 ()=>{ a() } 还是没法知道里面依赖了 msg。

经过对 此处代码 的验证,可以猜测 vue 应该是采用的第一种方案,还是去看 vuejs/composition-api 的代码来研究一下吧

watchEffect 的实现在 src/apis/watch.ts#L368 , 代码如下

export function watchEffect(
  effect: WatchEffect,
  options?: WatchOptionsBase
): WatchStopHandle {
  const opts = getWatchEffectOption(options)
  const vm = getWatcherVM()
  return createWatcher(vm, effect, null, opts)
}

这里没啥好看的,继续看 createWatcher : src/apis/watch.ts#L205 , 代码如下(精简了代码)

function createWatcher(
  vm: ComponentInstance,
  source: WatchSource<unknown> | WatchSource<unknown>[] | WatchEffect,
  cb: WatchCallback<any> | null,
  options: WatchOptions
): () => void {

  let running = false
  const getter = () => {
      // preventing the watch callback being call in the same execution
      if (running) {
        return
      }
      try {
        running = true
        ;(source as WatchEffect)(registerCleanup)
      } finally {
        running = false
      }
    }
   const watcher = createVueWatcher(vm, getter, noopFn, {
      deep: options.deep || false,
      sync: isSync,
      before: runCleanup,
   })
}

这里可以看到 16行的 (source as WatchEffect)(registerCleanup) 基本验证了猜测,继续看 createVueWatcher : src/apis/watch.ts#L170

https://www.typescriptlang.org/zh/play?#code/DYUwLgBAJiAOBcEBKIBmAeArgOwNbYHsB3bAPgG0BdCAXgioFgAoAYwOwGdIZYAZASzy0I2EEQgB1EAENcAWWmx0KDDnzEyAGggBlcOgBiOFmH7tSpABQBKZszABPWCGRp0AFVLCA3hABu0sCYIIjuEAC+zKjGpuwQAE5unpZ+odaIKh5e3swQeRCgkAFBLnR+ANy5+YlgmPHYEDlM+S0QHOD+gcEpaY1Vra3FwcJ+-QP5bJyQLABGAlzCPAJ4AHQA5uCWYAAW-By2zeMt-KgQlrPzYNZ9h0cDF3tgK6gE8QCi0izb5zO0XrM2A53fKRW6tcKaMYtDZFLogGyhG7AvI8FawTAcb47PZA5E1OoNIYgKEgsag0FRGJmBpsAC26LAICgWUsMMZ8UQNj+EHc6VcGE8SIm7AWROEbJA8RsY0mCzpDKZKmEiVQKThuJRcGerw+X0sPG5TSOhQgDwWdCWglw602PA1rROZwAhGarkLga7hKJxHowNKwUdLat2n6eNpXfaWqCjq6VtIoFBLFyaNkSfcCPTMIyoCoVmK6BKpZGQfbwvaDXRGGD8fVTRmFTm0MwKawRZBpMq0JYAMwHWXTDt0eVZplJ64p911zgEUArYAENaWaR59VjGsNZdE5sHZgh9z8WkgAhZseGsabuHCADsze0AEYAAxPg57g9Hk-J1Ngi8lYQADhlEUZxAOcF3OH9ggOCEIAAJifB8X3AABJbB2WKU8JyNfIIJAABqXDbwgbt4OsIA

链接到此文档的相关文档

了解 vue composition-api 原理

by 崮生 from 崮生 • 一些随笔 🎨,欢迎 赞助本文
本文欢迎分享与聚合,全文转载未经授权( 联系我)不许可。

神仙散棒槌IT源点monaco-editor崮生 • 一些随笔 🎨 赞助我 copyright © 2018.11.6 - 2021.10 湘ICP备18021783号 GIT HUB


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK