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 的基础架构, ...
随机推荐
- 基于 Agora SDK 实现 Windows 端的多人视频互动(基于3.6.2版本)
本文介绍如何通过 Agora SDK 在 Windows 平台快速实现互动直播.互动直播和实时通话的区别就在于,直播频道的用户有角色之分.你可以将角色设置为主播或者观众,其中主播可以收.发流,观众只能 ...
- Maven安装详解
Maven Maven是apache软件基金会旗下的一个开源项目,是一款用于管理和构建Java项目的工具. Maven的作用? 先来简单介绍一下Maven的作用 (1)依赖管理 方便快捷的管理项目依赖 ...
- 改善与提高linux系统的音质
当初装Linux系统的时候,我就发现了,deepin和ubuntu的linux平台音质和Windows平台下的音质不一样.硬件参数没变,歌曲音频文件相同的情况下,linux播放歌曲的时候动态和音乐细节 ...
- .Net 6.0定义全局当前身份缓存对象
背景: 当前身份缓存对象顾名思义就是:当前登录的用户身份对象,那它解决了什么问题呢?其实在我们日常开发过程中经常能用的到几乎是必备的,就比如我给某个表插入数据时需要创建人或者一些权限的访问,都得用到当 ...
- BrightlyPro - 照片视屏后期自动调色增亮工具
BrightlyPro 自动增强您的照片和视频,你最需要它.通过一个滑块,BrightlyPro 立即使您的照片自适应地亮起来,同时保持光影之间令人愉悦的平衡,而不会扭曲已经点亮的区域. 下载 ➤ B ...
- MySQL 中索引是如何实现的,有哪些类型的索引,如何进行优化索引
MySQL 中的索引 前言 索引的实现 哈希索引 全文索引 B+ 树索引 索引的分类 聚簇索引(clustered index) 非聚簇索引(non-clustered index) 联合索引 覆盖索 ...
- 搭建react的架手架
1.回顾 cnpm i @vue/cli -g ----- 4的脚手架 ------ webpack 4 cnpm i @vue/cli@3 -g ----- 3的脚手架 ------ webpack ...
- PyQt5学习 (1)--对象的基本操作、QObject
参考视频:[Python-GUI编程-PyQt5 (少)] https://www.bilibili.com/video/BV17J41177ro/?share_source=copy_web& ...
- Junit环境配置和在IDEA中使用Junit学习记录
Junit环境配置 步骤1:检查电脑中Java环境是否配置成功 因为JUnit 是 Java 的一个框架,所以最根本的需要是在你的机器里装有 JDK. 1.1 进入cmd控制台界面,输入java/ja ...
- 当前标识(IIS APPPOOL\derl)没有对“C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files”的写访问权限。
解决方法:运行cmd 执行以下指令 1.检查用户组,找到iis相关的用户组, 2.将电脑登录用户添加到该组 3.为指定的用户或用户组授予权限,使其可以访问 IIS 元数据库和 ASP.NET 使用的其 ...