关于destroy函数销毁阶段

440 阅读1分钟

代码:src/core/instance/lifecycle.js

/**
 * 完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。🚀🌟🌟🌟🌟🌟🌟
 */
  Vue.prototype.$destroy = function () {
    const vm: Component = this
    if (vm._isBeingDestroyed) { // 该属性标志着当前实例是否处于正在被销毁的状态
       // 表示实例已经销毁
      return
    }
    // 调用 beforeDestroy 钩子,该钩子函数的调用标志着当前实例正式开始销毁🚀
    callHook(vm, 'beforeDestroy')

    /**
     * 进入了当前实例销毁的真正逻辑。🚀
     */
    // 标识实例已经销毁
    vm._isBeingDestroyed = true
    // remove self from parent
    const parent = vm.$parent
    // 把自己从老爹($parent)的肚子里($children)移除
    /**
     * 🌟
     * 如果当前实例有父级实例,同时该父级实例没有被销毁并且不是抽象组件
     * 就将当前实例从其父级实例的$children属性中删除
     */
    if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
      remove(parent.$children, vm)
    }

    /* 开始将自己身上的依赖追踪和事件监听移除。🚀
    teardown watchers 移除依赖监听
    实例身上的依赖包含两部分:
    一部分是实例自身依赖其他数据,需要将实例自身从其他数据的依赖列表中删除;
    另一部分是实例内的数据对其他数据的依赖(如用户使用$watch创建的依赖),也需要从其他数据的依赖列表中删除实例内数据。
    所以删除依赖的时候需要将这两部分依赖都删除掉。
    */
    if (vm._watcher) { // 将实例自身从其他数据的依赖列表中删除,teardown方法的作用是从所有依赖项的Dep列表中将自己删除
      vm._watcher.teardown() // 所有实例内的数据对其他数据的依赖都会存放在实例的_watchers属性中
    }
    let i = vm._watchers.length // 遍历
    while (i--) {
      vm._watchers[i].teardown() // 所有实例内的数据对其他数据的依赖都会存放在实例的_watchers属性中
    }
    // remove reference from data ob
    // frozen object may not have observer.响应式的内容
    if (vm._data.__ob__) { // 移除实例内响应式数据的引用
      vm._data.__ob__.vmCount--
    }
    // call the last hook... 给当前实例上添加_isDestroyed属性来表示当前实例已经被销毁,同时将实例的VNode树设置为null
    vm._isDestroyed = true
    // invoke destroy hooks on current rendered tree 调用 __patch__,销毁节点
    vm.__patch__(vm._vnode, null)
    // fire destroyed hook 调用 destroyed 钩子
    callHook(vm, 'destroyed')
    // turn off all instance listeners. 关闭实例的所有事件监听
    vm.$off()
    // remove __vue__ reference
    if (vm.$el) {
      vm.$el.__vue__ = null
    }
    // release circular reference (#6759)
    if (vm.$vnode) {
      vm.$vnode.parent = null// 断开节点的联系
    }
  }
}