当前位置: 首页 > news >正文

cuda合并访问的要求_合并配置、组件注册、生命周期和异步组件

合并配置:1、了解外部调用场景(new Vue)的配置合并;2、了解组件场景的配置合并

if (options && options._isComponent) {
      //将 options 和 Vue.options 合并到 Sub.options,合并的结果保留在 vm.$options
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }

e6345136dafb4a7f3fb76e14a6df2f20.png

在执行 this._init(options) 会有两种合并方式,回调用这个 init 函数有两种情况,一种是初始化 Vue 时,一种是组件初始化时,第一种情况下,会进入到 else 逻辑,mergeOptions 函数实际上就是将 Vue.options 和 options 作合并,Vue.options 在初始化全局 Vue API 时被定义,实际上就是将三个属性添加给 Vue.options,并且都初始化为一个对象:

Vue.options.components = {}
Vue.options.directives = {}
Vue.options.filters = {} 

mergeOptions(parent,child,vm?) 主要是把 parent 和 child 这两个对象根据一些合并策略,合并成一个新对象,并返回这个新对象。在这个过程中会将 extends 和 mixins 扩展或者混合的对象也会合并进来。

接下来看组件初始化合并的情况:

由于组件的构造函数(Sub)是通过 Vue.extend 继承自 Vue 的,在生成组件构造函数的过程中,会将 Vue.options 和 options 进行合并,将结果存储在 Sub.options 中,并且合并 options 的过程会走到 initInternalComponent(vm, options) 的逻辑,这个函数会将 Sub.options 赋值给 vm.$options,因此我们可以通过 vm.$options 访问到 Vue.options 和 自定义 options。

Sub.options = mergeOptions(
    Super.options, //Super 为 Vue
    extendOptions //自定义的 options
  )

组件注册目标:1、了解全局组件和局部组件的注册方式;2、了解两种注册的差异

注册全局组件方法:Vue.component(tagName, options)

32934d6447c3e28bd4a8721dfe3a87ef.png

在文件入口,会初始化全局 Vue API,Vue.component 就在其中被定义为一个返回该组件构造函数的方法,并且该方法会将该组件构造器储存在 this.options.component.id 属性中,其中 this 代表了 Vue,因此 Vue.options.component.id 可以访问到 Sub.options,而上面讲合并配置时说到,Vue.options 和 自定义 options 合并的结果存放到了 Sub.options,因此注册全局组件的方式是将自定义的 options 扩展到了 Vue.options 中,而在每个生成每个组件构造函数的过程中,都会将 Vue.options 合并到 vm.$options 中,所以最终全局组件可以被任意其他组件使用。

export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]

ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        //看这段 if 语句
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        //看这句
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })

然后在组件实例化阶段,即 new Sub() 的过程中,会进入到组件初始化,继而进入到配置合并的流程,initInternalComponent(vm, options) 会将 Sub.options 存放到 vm.$options 中。

注册局部组件方法,例如:

import HelloWorld from './components/HelloWorld'

export default {
  components: {
    HelloWorld
  }
}

其实就是走 initInternalComponent(vm, options) 这个逻辑,会将 components 合并到 vm.$options.components 上,所以 vm 可以访问到 HelloWorld 这个子组件。但只有注册了这个局部组件的组件才能访问这个局部组件,因为局部组件的 options 并没有扩展到 Vue.options 中。

生命周期目标:1、了解 Vue.js 有哪些生命周期;2、了解各个生命周期的时机以及我们能作的事情;

依然从源码角度来分析:

initLifecycle(vm) //初始化生命周期
initEvents(vm) //初始化事件
initRender(vm)
callHook(vm, 'beforeCreate') //执行钩子
initInjections(vm) // resolve injections before data/props
initState(vm) 
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created') //执行钩子

beforeCreate 和 created

当 init 时,会先进行事件和生命周期的初始化,然后执行 beforeCreate 钩子,initState 这个函数会初始化 props、data、methods、watch、computed 等属性,那么显然 beforeCreate 钩子就 不能获取到 props 和 data 中定义的值,也不能调用 methods 中定义的函数,之后执行 created 钩子。

beforeMount 和 mounted

发生在 $mount 过程中,在 vm._render 函数渲染 vnode 之前,执行了 beforeMount 钩子,在将 vnode patch 到真实 DOM 后,执行了 mounted 钩子,但是 new Vue 中的 mounted 钩子和组件 mounted 钩子执行时机是不同的,当增加渲染 wather 后,就会执行 new Vue 的 mounted 钩子,当组件 vnode patch 到真实 DOM 后,会执行 invokeInsertHook 函数,这个函数会将 insertedVnodeQueue 数组(在子组件初始化过程中,会不断地将当前子组件 vnode push 到 insertedVnodeQueue 数组中。)中的每一个组件 vnode 都执行它们对应的 insert hook(组件钩子),这个组件钩子会执行 mounted 钩子。

beforeMount 先父后子

Mounted 先子后父,原因是 push 进 insertedVnodeQueue 数组的组件 vnode 是先子后父

beforeUpdate 和 updated

了解响应式原理之后,再详细写这个部分,简单来说就是当数据发生改变时,会执行这个两个钩子。要求是必须在 mounted 钩子执行完之后。

beforeDestroy 和 destroyed

它们的执行时机是在组件销毁的阶段,了解组件销毁原理之后,再详细写这部分。

beforeDestroy 先父后子

destroyed 先子后父

异步组件有三种实现方式:1、工厂函数;2、promise 对象;3、高级异步组件

异步组件优化首屏加载效率的一种有效方式,可以让加载的资源包变小,同时 JS 执行时间减少,渲染的 DOM 树体积变少。

工厂函数:注册组件时,不再是对象,而是一个工厂函数,工厂函数中使用异步加载组件的方式:

//回调函数来实现异步
Vue.component('async-example', function (resolve, reject) {
   // 这个特殊的 require 语法告诉 webpack
   // 自动将编译后的代码分割成不同的块,
   // 这些块将通过 Ajax 请求自动下载。
   require(['./my-async-component'], resolve) //这是一个异步加载过程,只有当结果返回后才会执行 resolve 回调函数
})

6b354c7a5d006f8516a7e3f7e5cc1420.png

工厂函数会被作为参数传入给 createComponent,进入到异步组件处理的逻辑,将工厂函数和 Vue 传给 resolveAsyncComponent 函数,以下是核心代码:

//once 函数通过闭包和标志位使 resolve 和 reject 只会执行一次
    const resolve = once((res: Object | Class<Component>) => {
      // cache resolved
      //这个函数将返回一个异步组件的构造器
      factory.resolved = ensureCtor(res, baseCtor)
      // invoke callbacks only if this is not a synchronous resolve
      // (async resolves are shimmed as synchronous during SSR)
      if (!sync) {
        //最终又会再一次进入到 createComponent,拿到异步组件构造器之后,之后的流程跟同步组件一样
        //之所以要强制渲染,是因为无法保证异步组件加载过程中的数据发生变化
        //但当异步加载完成后,必须再次渲染,必须再次执行 
        //第一次渲染 createComponent 生成的是空 vnode最终被渲染成了注释节点,而这一次是要生成异步组件 vnode
        forceRender(true)
      } else {
        owners.length = 0
      }
    })

异步组件第一个渲染时只会渲染出一个注释节点,作为异步组件加载完成之前的占位符,当异步组件加载成功后,就会执行 resolve 函数,就会进入到 forceRender 进行第二次渲染,会直接获取到异步组件的构造函数,最终生成一个异步组件的 vnode,之后的流程跟同步组件是一样的,最终组件节点会代替注释节点。

Promise 异步组件:配合了 webpack 的 import 语法,返回一个 promise 对象

//promise 来实现异步
Vue.component('async-example', () => import('my-async-component')
//在 vue 源码中,这样定义了:
let res = factory(resolve, reject);
//在异步组件加载得到返回结果后
res.then(resolve, reject)
PS:无论哪种方式,传入的参数 resolve 和 reject 都是源码中定义好的方法,前者在加载到组件对象后,会进行重新渲染,渲染组件,后者也会重新渲染,如果有 error 组件,就会渲染出 error 组件,这个可以用下面的高级组件进行配置。

高级组件:为了处理加载过程中以及加载失败的情况

const AsyncComp = () => ({
  // 需要加载的组件。应当是一个 Promise
  component: import('./MyComp.vue'),
  // 加载中应当渲染的组件
  loading: LoadingComp,
  // 出错时渲染的组件
  error: ErrorComp,
  // 渲染加载中组件前的等待时间。默认:200ms。
  delay: 200,
  // 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
  timeout: 3000
})
Vue.component('async-example', AsyncComp)
异步组件第一次执行时,看 delay 是否为 0,如果为 0,则直接渲染 loading 组件,否则就渲染成一个注释节点(异步组件的占位符);
之后再次渲染会有四种状态:
1、reject 状态:如果异步组件加载失败,则渲染 error 组件;
2、resolve 状态:如果异步组件加载成功,则渲染加载成功的组件 vnode;
3、loading 状态:如果异步组件在加载中,则渲染 loading 组件;
4、timeout 状态:如果过了 timeout 的时间还没有加载成功,则渲染 error 组件

有人会有疑问:异步组件会渲染两次(使用高级组件时可能会渲染三次),是不是会不利于页面性能优化?

首先我们使用异步组件是为了按需加载,最主要的功能是优化首屏性能,可以让加载的资源包大小变小,同时 JS 执行时间减少,渲染的的 DOM 树体积也变少,而异步加载组件后的渲染,已经是第二次渲染,非首屏渲染了,影响的不是首屏性能。但是由于异步组件增加了 HTTP 请求,所以当资源包不是特别大的时候(app.js 不大于 1 MB 时),使用异步组件会有相反的作用。

相关文章:

  • NGS 数据过滤之 Trimmomatic
  • js 5秒钟后执行某个函数_前端面试题: (JavaScript 第5期)
  • SRA数据库及其数据的下载
  • wps如何在目录里面打省略号_Word中如何引用?3个实用小技巧帮你工作效率翻倍!...
  • asp.net图书管理系统源码_[源码和文档分享]基于B树实现的图书管理系统
  • SRA下载到分析
  • 多个子流程_协程工作流程的实现
  • Permission denied
  • wps交叉表_WPS文字小工具大用途—交叉引用的使用方法
  • 使用Trinity进行转录组组装
  • linux ssh连接交换机_【交换机】交换机如何配置ssh管理
  • python股票分析入门_学习用Python分析股票数据(入门)
  • Aspera 下载_SRA原始数据下载
  • keil5怎么配置程序风格_分享一个在Keil开发环境中配置代码格式化工具Astyle(美化代码风格)...
  • 01-rna-seq从头开始 卖萌哥
  • C语言笔记(第一章:C语言编程)
  • React Native移动开发实战-3-实现页面间的数据传递
  • VuePress 静态网站生成
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 从零开始的无人驾驶 1
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 区块链技术特点之去中心化特性
  • 使用common-codec进行md5加密
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 用Canvas画一棵二叉树
  • 最近的计划
  • gunicorn工作原理
  • HanLP分词命名实体提取详解
  • python最赚钱的4个方向,你最心动的是哪个?
  • 阿里云服务器购买完整流程
  • 数据库巡检项
  • ​queue --- 一个同步的队列类​
  • (1)(1.13) SiK无线电高级配置(五)
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (Git) gitignore基础使用
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (四)c52学习之旅-流水LED灯
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET委托:一个关于C#的睡前故事
  • .NET中GET与SET的用法
  • .NET中统一的存储过程调用方法(收藏)
  • /3GB和/USERVA开关
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @我的前任是个极品 微博分析
  • []FET-430SIM508 研究日志 11.3.31