vue 中render执行流程梳理
用了多年vue 今天对自己了解的render 做一个梳理
一、使用template模板
先从vue 初始化开始:
众所周知项目的main.js中定义了
var app = new Vue({})这vue初始化操作
其实他会执行到
这个方法中的_init函数,在这个方法执行一些列的初始化后,判断$options是否定义el,如果定义调用
vm.$mount(vm.$options.el)函数,这个函数其实是在entry-runtime-with-compiler.js中定义的,if (!options.render) {}判断是否定义了render函数,如果未定义再判断是否定义template,如果定义直接调用‘compileToFunctions’函数将template编译成为一个匿名函数,这里先借一个简单案例,打个断点测试下执行流程
import Vue from 'vue'
/**
* 使用 template 方式
*/
var app = new Vue({
el:'#admin',
template:'<ul :class="bindCls" class="list" v-if="isShow">'+
'<li v-for="(item,index) in data" @click="clickItem(index)">{{item}}:{{index}}</li></ul>',
data(){
return {
bindCls:'a',
isShow:true,
data:['A','B','C','D']
}
},
methods:{
clickItem(index){
console.log(index);
}
}
})
最后render匿名函数内容是这样的
(function anonymous(
) {
with(this){return (isShow)?_c('ul',{staticClass:"list",class:bindCls},_l((data),function(item,index){return _c('li',{on:{"click":function($event){return clickItem(index)}}},[_v(_s(item)+":"+_s(index))])}),0):_e()}
})
看似一段简短的render,其实生成这个render是一个相当复杂的过程
1、将template 转换为render 字符串
首先在compiler 文件中的index.js中
定义了createCompiler常量该值为create-compiler.js里的createCompilerCreator函数,同时将baseCompile函数传入
而createCompilerCreator返回的是一个createCompiler函数而该createCompiler函数最后的返回值是一个
{ compile, compileToFunctions: createCompileToFunctionFn(compile) } 对象,
该对像中createCompileToFunctionFn其实是to-functiuon.js中定义的,目的就是把compile作为参数传入,进行一些列校验合并等
再回过头来调用compile实现编译操作,取得最后compile编译的结果,其实准确说是baseCompile编译后的结果,因compile中其实是调用baseCompile进行模板编译的(其中的通过parse 生成ast和generate生成code就不细说了,其实这个code中就包含了render),
而createCompileToFunctionFn取得了编译后的render并使用createFunction将其转为一个匿名函数,就是上面看见的样子了
而createCompilerCreator值返回到entry-runtime-with-compiler.js中的Vue.prototype.$mount函数中,同时将render挂载到了vu.$options上,再次调用runtime下index.js中的Vue.prototype.$mount函数
此时函数中又调用到了core/instance/lifecycle中的mountComponent函数;mountComponent函数在new Watcher中执行get(), 调用了updateComponent函数; 开始了执行vm._render()的操作,这个函数其实就定义在instance/render.js中;
这一连串的调用最终将template编译为render,又将其使用createElement编译为vdom,再使用__patch__初始化事件将其生成真实dom插入到页面的body中
看文字很不直观,这里截几个源码图来看看
2、render执行调用
好了现在就来看看render究竟是怎么执行的,其实他的执行也挺简单直接使用call进行调用,如
这个里面的_renderProxy其实是在init.js中绑定的
其实就是在开发阶段做一些校验,再将vm 使用proxy代理一个handlers将其返回,而生产环境就是vm实例
而vm.$createElement是上面一个initRender中初始化了,其实这个主要是用于我们手写render用的
然render.call(vm._renderProxy, vm.$createElement),中render就是上面说过的匿名函数
(function anonymous(
) {
with(this){return (isShow)?_c('ul',{staticClass:"list",class:bindCls},_l((data),function(item,index){return _c('li',{on:{"click":function($event){return clickItem(index)}}},[_v(_s(item)+":"+_s(index))])}),0):_e()}
})
他里面的with作用更改作用域链,执行时会首先从局部去查找里面的函数,如_c(),如果局部没有就会到其绑定的作用域this中去找,在render.call时我们知道其实是将vm传入了,而这个_c()就是上面initRender中定义的
,
而其他的如_e(),_l()这些就是在render-helper中了
而_c()又对应一个createElement函数这个就是真正的创建vdom的地方了,到此render 编译template就完成了
二、手写render
import Vue from 'vue'
var app = new Vue({
el:'#admin',
render(createElement){
return createElement('div',{
attrs:{
id:'admin'
}
},this.message)
},
data(){
return {
message:'Hello vue'
}
}
})
而手写render 其实是一样的,只是在entry-runtime-with-compiler.js不会进行compileToFunctions编译,而直接调用mount,而上面代码中render里的createElement是在render.call(vm._renderProxy, vm.$createElement)直接将createElement函数作为参数传入的,最后将该函数返回值返回给 Vue.prototype._update,然后将其使用vm.__patch__转为真实dom数插入到页面中
三、自定义函数进行模拟
手动写render
var vm = function(){}
function createEl(a,b){
console.log(a,b);
}
vm.$createEl = (a,b) => createEl(a,b);
render.call(vm,vm.$createEl); // div1 div2
function render(createEl){
return createEl('div1','div2');
}
2、编译 template为render
// vm构造函数
var vm= function(){};
// 创建vdom函数
function createEl(a,b){
console.log(a,b);
};
// 模拟获得编译后的render 字符串
var compiledRender = "with(this){return _c('div1','div2')}";
// 将其转换为函数
var render= new Function(compiledRender);
// 为vm定义_c函数
vm._c = (a,b) => createEl(a,b);
// 为vm定义$createEl 函数
vm.$createEl = (a,b) => createEl(a,b);
// 执行调用
render.call(vm, vm.$createEl ); // div1 div2
到此把整个render 流程理了一遍,感谢阅读有不正确处欢迎指正和探讨,学习永不止步,探索从未停止。
vue 中render执行流程梳理的更多相关文章
- tf中计算图 执行流程学习【转载】
转自:https://blog.csdn.net/dcrmg/article/details/79028003 https://blog.csdn.net/qian99/article/details ...
- Spring启动执行流程梳理
注:本文梳理启动流程使用的Spring版本:4.0.2.RELEASE 使用spring配置,都需要在web.xml中配置一个spring的监听器和启动参数(context-param),如下: &l ...
- [转]两表join的multi update语句在MySQL中的执行流程分析
出自:http://hedengcheng.com/?p=209 两表join的multi update语句,执行结果与预计不一致的分析过程 — multi update结论在实际应用中,不要轻易使用 ...
- Vue中render: h => h(App)的含义
// ES5 (function (h) { return h(App); }); // ES6 h => h(App); 官方文档 render: function (createElemen ...
- vue中render: h => h(App)的详细解释
2018年06月20日 10:54:32 H-L 阅读数 5369 render: h => h(App) 是下面内容的缩写: render: function (createEleme ...
- Java 中控制执行流程
if-else 非常常用的流程控制非 if-else 莫属了,其中 else 是可选的,if 有两种使用方式 其一: if (Boolean-expression) { statement; } 其二 ...
- web项目中的执行流程参数传递详解
还是从这个图开始讲解: struts2中有一个存放数据的中心:值栈.(值栈里面有map和对象栈) 首先:值栈的作用范围是一个请求:request作用域(一个请求是代表的一个过程,即页面点击到数据返回到 ...
- vue中beforeRouteEnter 执行的时机及运用的误区?
beforeRouteEnter钩子 beforeRouteEnter (to, from, next) { console.log(this); //undefined,不能用this来获取vue实 ...
- MySQL之执行流程
最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新 ...
- 一条SQL语句在MySQL中如何执行的
本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...
随机推荐
- VsCode里面在JavaWeb项目里面配置Maven环境详解
1.在之前已经新建完成一个JavaWeb项目的基础上开始 2.设置里面搜索Maven,找到这个,然后进行定位 3.将Tomcat Server配置进去(右上角有一个加号) (对于已经学过Java的并不 ...
- Weak Encryption 弱加密安全问题处理
Weak Encryption Abstract 程序使用了弱加密算法,无法保证敏感数据的保密性. Explanation 陈旧的加密算法(如 DES)再也不能为敏感数据提供足够的保护了. 加密算法依 ...
- .Net7 CLR的调用函数和编译函数
前言 .Net运行模型,无非就两个过程.一个是调用入口函数,另外一个就是编译入口函数.前者主调用,后者主编译. 概括 一:入口函数:RunMainInternal 所有的.Net程序,包括控制台,We ...
- 手机号码归属地的自动查询.py(亲测有效)
import requests url = "http://m.ip138.com/sj.asp?mobile=" kv = {'user-agent':'Mozilla/5.0' ...
- 第三章3.3 selenium基础
seleniumIDE:是一款可以实现录制回放的操作:存在可视化窗口进行录制回放操作:它属于firefox(chrome)浏览器的插件;安装方式:两种 : 1.下载安装包离线安装2.在线安装 注意:不 ...
- python调用打印机打印文件,图片,pdf等
引言 python连接打印机进行打印,可能根据需求的不同,使用不同的函数模块. 如果你只是简单的想打印文档,比如office文档,你可以使用ShellExecute方法,对于微软office的文档.p ...
- [Java SE]JDK版本特性解读:@PostStruct[JDK1.6-JDK1.8]
1 @PostStruct 1.1 概述 定义及用途 @PostConstruct(javax.annotation.PostConstruct)注解好多人以为是Spring提供的.而实际上是Java ...
- Java 生成海报
最近项目有个功能是生成海报 一个背景图片,一个二维码图片 将两个图片合并成一个图片. 写了一个工具类,需要的朋友自取. 1 @Component 2 public class PictureUtil ...
- Linux搭建docker
### 1. 查看系统的内核版本 ```bash[root@wide ~]# uname -r3.10.0-1160.el7.x86_64``` ### 2. 将yum更新到最新版本 ```bash[ ...
- DyLoRA:使用动态无搜索低秩适应的预训练模型的参数有效微调
又一个针对LoRA的改进方法: DyLoRA: Parameter-Efficient Tuning of Pretrained Models using Dynamic Search-Free Lo ...