vue3.2中有关getCurrentInstance函数取值的部分源码讲解

927 阅读2分钟

题引:

在我们vue3中,由于过多的全局变量导致我们挂载到vue实例上。那么在setup语法糖的时候,想要那this就得借用 getCurrentInstance 函数来实现。但是在开发的时候,我们会发现有时候拿到的返回值是 null 。这得来说道说道。

结论:

在这里我们直接给出测试代码,我们可以得到一个明显的结论。

<script setup>
import {
  getCurrentInstance,
} from "vue";
import HelloWorld from "./components/HelloWorld.vue";

// 同步获取有值
let proxy = getCurrentInstance()
console.log(getCurrentInstance());
console.log(proxy);

let promise = new Promise((resolve, reject) => {
  resolve(getCurrentInstance()) // new Promise里的回调函数是同步任务,即也有值
})

// 定时器为异步,则获取为null
setTimeout(() => {
  console.log(getCurrentInstance());
  console.log(proxy);  // 这里有值是因为它已经保存了一份引用地址
});

// 点击事件也是为null,因为在触发点击的时候 getCurrentInstance函数返回 currentInstance = null
const click = () => {
  console.log(getCurrentInstance());   // null
  promise.then(res => {
    console.log(getCurrentInstance());  // null
    console.log(res); // 有值,promise的resolve值
  })
};
</script>

<template>
  <button @click="click">test</button>
</template>

结论: getCurrentInstan 函数只能在 同步任务 执行才有值,放在 异步任务或者函数体 里面为 null

剖析:

在vue3.2的版本中是这个路径:@vue>runtime-core>dist>runtime-core.esm-bundler.js
直接给出 getCurrentInstance 的调试栈路径,也只讲框框中的函数。如下:

image.png

先贴上 getCurrentInstance 函数的源码。 image.png

now,我们从 mountComponent 函数开始讲解。

image.png

image.png

该函数在组件挂载时触发,并且会调用 createComponentInstance 函数创建vue组件实例,里面就是我们使用ref或者getCurrentInstance时获取的对象属性。
接着处理一些边缘判断,再触发 setupComponent 函数。

image.png

我们可以理解 setupComponent 函数为一个阀门值,如果组件实例里面是有状态的的话就会触发setup的初始化函数入口 setupStatefulComponent

image.png 这里是setup的内部处理函数。里面主要分了以下几个处理

  1. 环境判断,对production环境进行特殊处理(不涉及getCurrentInstance所以不深入)
  2. 对实例的属性进行添加,如对实例的上下文进行proxy数据劫持进而赋值给proxy属性(这相当于我们vue2的 this
  3. 从组件中解构setup函数
  4. 调用createSetupContext函数给setup的上下文添加属性,如attrs、slots、emit
  5. 紧接着调用setCurrentInstance函数把vue实例赋值给currentInstance变量
  6. 接下来就是自调用callWithErrorHandling函数,在该函数内部进行fn(...args)。(fn即setup函数,args即setup的上下文)
  7. 调用完将currentInstance变量赋值为null
  8. 对setup函数的执行结果进行处理

这就是setup内部的重要处理流程,这也就是为什么我们在同步任务中通过 getCurrentInstance 函数可以获取vue3实例,而在异步任务中取不到的原因。就是因为人家内部在setup函数同步调用完之后就置空了,异步是不可能获取到的。所以这也是为什么要用一个变量来保留。

结尾

最后,文章如有解释不对之处,欢迎评论区交流,如果感觉有所收获,还请点赞支持!